суббота, 2 января 2016 г.

Новый робот

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


К сожалению видео получилось не очень. Снимаю мало. Разбираться в тонкостях нет ни времени, ни желания. Видно что недостаточно света. Освещение искусственное. Можно это исправить настройками? Менять освещение? Я понятия не имею. Как нибудь постараюсь разобраться. С естественным освещением сейчас тоже не очень. Дни короткие и пасмурные.



Схема обычная. Трехколесная. Сделана из подручных материалов. Что можно приклеить на двусторонний скотч, то клеится на скотч. Пластиковые стяжки наше всё. Болты и гайки это последнее средство. У такого подхода есть как достоинства так и недостатки. Для изготовления небольшого прототипа это вполне приемлемые решения.

Фото 1


Фото 2


Фото 3


Фото 4


В этой платформе используются шаговые двигатели.


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

Переходники для крепления колес под трех миллиметровый вал.


Мои переходники свободно одеваться не захотели. Пришлось помочь тисочками.

Колеса от радиоуправляемых моделей автомобилей масштаба 1/10.


Внешний диаметр колеса (Outer Diameter): 65 mm
Диаметр пластикового диска (Wheel Diameter): 52 mm
Размер переходника (Wheel Drive Hex): 12 mm
Ширина колеса (Wheel Width): 26 mm

Для управления моторами используются готовые драйвера на L293D. Они дешевые. И к ним просто подключить моторы. Есть все нужные разъемы. Не нужно ничего паять.


Драйверами двигателей управляет ардуино уно.


Для удобства используется Arduino UNO Sensor Shield V5


Интересная платка. Есть клеммы для подключения аккумулятора. Если напряжение выдаваемое аккумулятором превышает 5 вольт, то необходимо удалить перемычку с SEL. Иначе ардуино сгорит. При этом ардуино останется без питания. Можно запитать уно от того же аккумулятора, но через стабилизатор самой ардуино. Выводы шилда vcc расположенные рядом с цифровыми пинами всегда соединены непосредственно с аккумулятором. На них будет тоже напряжение, что и на аккумуляторе. А вот на выводах vcc находящихся рядом с аналоговыми пинами будут 5 вольт выдаваемые стабилизатором ардуино. Перед подключением всякого разного к шилду не повредит и напряжение мультиметром проверить.

Питается робот от двух соединенных последовательно Li-ion аккумуляторов 18650.


Обратите внимание на то, что эти аккумуляторы пожароопасны и взрывоопасны. Заряжать их следует только специальным зарядным устройством (процесс необходимо постоянно контролировать лично). Также их нельзя разряжать ниже определенного напряжения. При падении напряжения ниже некоторого порога, такие аккумуляторы выходят из строя. Для разных моделей литиевых аккумуляторов величина минимального напряжения различна. Поэтому настоятельно рекомендуется использовать защищенные аккумуляторы. В них встроена специальная платка предотвращающая критический разряд и перезаряд аккумулятора. Однако абсолютная безопасность при использовании таких аккумуляторов не гарантируется. Тщательно проверяйте все цепи своих конструкций перед подключением литиевых аккумуляторов. Аккумуляторы должны быть способны выдать ток потребляемый устройством. Это должен быть штатный режим работы аккумулятора, а не кратковременно допустимый пиковый ток. Иначе ничего хорошего не ждите.

Моя конструкция потребляет около 1.5 ампера.

Одной обмотке моего шагового двигателя нужно
(4.2 + 4.2) / 26.0 = 0.323 A

При одновременной запитке двух обмоток будет
0.323 * 2.0 = 0.646 A

В платформе используется два двигателя
0.646 * 2.0 = 1.292 A

Не стоит забывать об ардуино и драйверах двигателей. Им тоже нужен ток.

Неплохо бы предусмотреть запас для дополнительного оборудования (разные сенсоры).

Итого. Ток разряда аккумулятора  должен быть более 3 амперов. Я заказал себе аккумуляторы с током разряда в 30 ампер. Для данного проекта многовато, но у меня на них большие планы. Когда получу, напишу.

Для аккумуляторов 18650 есть специальные батарейные отсеки.


Подавать питание на ардуино удобно через Power Plug Connector Adapter 2.1*5.5 mm


Закончу рассказ об электрической части описанием соединений компонентов.

Подключение шагового двигателя к драйверу.

stepper motor --- driver
A1 --- A+
A2 --- A-
B1 --- B+
B2 --- B-
VCC --- VIN

Питание драйвера двигателя.

driver --- battery (7.4 V)
VIN --- +
GND --- -

Настройки драйвера двигателя.

driver --- driver
EN1 --- VCC
EN2 --- VCC

Подключение драйвера правого двигателя к ардуино.

driver --- arduino uno
GND --- GND
IN1 --- D11
IN2 --- D10
IN3 --- D9
IN4 --- D8

Подключение драйвера левого двигателя к ардуино.

driver --- arduino uno
GND --- GND
IN1 --- A3
IN2 --- A2
IN3 --- A1
IN4 --- A0

Код. В данной статье я приведу лишь простую тестовую программу.

////////////////////////
//
// Arduino Uno
//
////////////////////////
//
// Sketch: Robot
//

#include <util/delay.h>

const unsigned char D1_IN1 = 11; // Digital Pin 11
const unsigned char D1_IN2 = 10; // Digital Pin 10
const unsigned char D1_IN3 = 9; // Digital Pin 9
const unsigned char D1_IN4 = 8; // Digital Pin 8

const unsigned char D2_IN1 = 17; // Analog Pin 3
const unsigned char D2_IN2 = 16; // Analog Pin 2
const unsigned char D2_IN3 = 15; // Analog Pin 1
const unsigned char D2_IN4 = 14; // Analog Pin 0

const unsigned char FORWARD = 1;
const unsigned char BACKWARD = 2;
const unsigned char RIGHT = 3;
const unsigned char LEFT = 4;

unsigned char step1 = 1;
unsigned char step2 = 1;

void driver1 (unsigned char direct)
{
    if ( direct == 1 ) step1 -= 1;
    if ( direct == 2 ) step1 += 1;

    if ( step1 == 0 ) step1 = 8;
    if ( step1 == 9 ) step1 = 1;

    if ( step1 == 1 )
    {
        digitalWrite(D1_IN1, LOW);
        digitalWrite(D1_IN2, HIGH);
        digitalWrite(D1_IN3, HIGH);
        digitalWrite(D1_IN4, HIGH);
    }

    if ( step1 == 2 )
    {
        digitalWrite(D1_IN1, LOW);
        digitalWrite(D1_IN2, LOW);
        digitalWrite(D1_IN3, HIGH);
        digitalWrite(D1_IN4, HIGH);
    }

    if ( step1 == 3 )
    {
        digitalWrite(D1_IN1, HIGH);
        digitalWrite(D1_IN2, LOW);
        digitalWrite(D1_IN3, HIGH);
        digitalWrite(D1_IN4, HIGH);
    }

    if ( step1 == 4 )
    {
        digitalWrite(D1_IN1, HIGH);
        digitalWrite(D1_IN2, LOW);
        digitalWrite(D1_IN3, LOW);
        digitalWrite(D1_IN4, HIGH);
    }

    if ( step1 == 5 )
    {
        digitalWrite(D1_IN1, HIGH);
        digitalWrite(D1_IN2, HIGH);
        digitalWrite(D1_IN3, LOW);
        digitalWrite(D1_IN4, HIGH);
    }

    if ( step1 == 6 )
    {
        digitalWrite(D1_IN1, HIGH);
        digitalWrite(D1_IN2, HIGH);
        digitalWrite(D1_IN3, LOW);
        digitalWrite(D1_IN4, LOW);
    }

    if ( step1 == 7 )
    {
        digitalWrite(D1_IN1, HIGH);
        digitalWrite(D1_IN2, HIGH);
        digitalWrite(D1_IN3, HIGH);
        digitalWrite(D1_IN4, LOW);
    }

    if ( step1 == 8 )
    {
        digitalWrite(D1_IN1, LOW);
        digitalWrite(D1_IN2, HIGH);
        digitalWrite(D1_IN3, HIGH);
        digitalWrite(D1_IN4, LOW);
    }
}

void driver2 (unsigned char direct)
{
    if ( direct == 1 ) step2 -= 1;
    if ( direct == 2 ) step2 += 1;

    if ( step2 == 0 ) step2 = 8;
    if ( step2 == 9 ) step2 = 1;

    if ( step2 == 1 )
    {
        digitalWrite(D2_IN1, LOW);
        digitalWrite(D2_IN2, HIGH);
        digitalWrite(D2_IN3, HIGH);
        digitalWrite(D2_IN4, HIGH);
    }

    if ( step2 == 2 )
    {
        digitalWrite(D2_IN1, LOW);
        digitalWrite(D2_IN2, LOW);
        digitalWrite(D2_IN3, HIGH);
        digitalWrite(D2_IN4, HIGH);
    }

    if ( step2 == 3 )
    {
        digitalWrite(D2_IN1, HIGH);
        digitalWrite(D2_IN2, LOW);
        digitalWrite(D2_IN3, HIGH);
        digitalWrite(D2_IN4, HIGH);
    }

    if ( step2 == 4 )
    {
        digitalWrite(D2_IN1, HIGH);
        digitalWrite(D2_IN2, LOW);
        digitalWrite(D2_IN3, LOW);
        digitalWrite(D2_IN4, HIGH);
    }

    if ( step2 == 5 )
    {
        digitalWrite(D2_IN1, HIGH);
        digitalWrite(D2_IN2, HIGH);
        digitalWrite(D2_IN3, LOW);
        digitalWrite(D2_IN4, HIGH);
    }

    if ( step2 == 6 )
    {
        digitalWrite(D2_IN1, HIGH);
        digitalWrite(D2_IN2, HIGH);
        digitalWrite(D2_IN3, LOW);
        digitalWrite(D2_IN4, LOW);
    }

    if ( step2 == 7 )
    {
        digitalWrite(D2_IN1, HIGH);
        digitalWrite(D2_IN2, HIGH);
        digitalWrite(D2_IN3, HIGH);
        digitalWrite(D2_IN4, LOW);
    }

    if ( step2 == 8 )
    {
        digitalWrite(D2_IN1, LOW);
        digitalWrite(D2_IN2, HIGH);
        digitalWrite(D2_IN3, HIGH);
        digitalWrite(D2_IN4, LOW);
    }
}

void robot (unsigned char command, unsigned char i)
{
    unsigned char direct1, direct2;

    if (command == FORWARD)
    {
        direct1 = 2;
        direct2 = 1;
    }

    if (command == BACKWARD)
    {
        direct1 = 1;
        direct2 = 2;
    }

    if (command == RIGHT)
    {
        direct1 = 1;
        direct2 = 1;
    }

    if (command == LEFT)
    {
        direct1 = 2;
        direct2 = 2;
    }

    while( i > 0 )
    {
        i -= 1;
        driver1(direct1);
        driver2(direct2);
        _delay_ms(20);
    }
}

void driver1_init (void)
{
    pinMode(D1_IN1, OUTPUT);
    pinMode(D1_IN2, OUTPUT);
    pinMode(D1_IN3, OUTPUT);
    pinMode(D1_IN4, OUTPUT);
    
    digitalWrite(D1_IN1, LOW);
    digitalWrite(D1_IN2, HIGH);
    digitalWrite(D1_IN3, HIGH);
    digitalWrite(D1_IN4, HIGH);
}

void driver2_init (void)
{
    pinMode(D2_IN1, OUTPUT);
    pinMode(D2_IN2, OUTPUT);
    pinMode(D2_IN3, OUTPUT);
    pinMode(D2_IN4, OUTPUT);
    
    digitalWrite(D2_IN1, LOW);
    digitalWrite(D2_IN2, HIGH);
    digitalWrite(D2_IN3, HIGH);
    digitalWrite(D2_IN4, HIGH);
}

void setup()
{
    driver1_init();
    driver2_init();
    _delay_ms(2000);
}

void loop()
{
    robot(FORWARD, 50);
    _delay_ms(1000);

    robot(BACKWARD, 50);
    _delay_ms(1000);

    robot(LEFT, 50);
    _delay_ms(1000);

    robot(RIGHT, 50);
    _delay_ms(1000);
}

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

В заключении скажу несколько слов о достоинствах и недостатках получившейся конструкции.

Момент развиваемый шаговым двигателем не зависит от частоты вращения вала. Момент является максимальным в довольно широком диапазоне скоростей. Частоту вращения вала коллекторного двигателя можно регулировать с помощью ШИМ. Но при этом меняется и момент развиваемый двигателем. Чем ниже частота вращения вала, тем меньше момент.

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

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

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

Из минусов можно отметить цену. Мощные шаговые двигатели не дешевле сравнимых коллекторных моторов с редукторами.

Для платформы на коллекторных моторах достаточно было бы одного драйвера на L293D. А для платформы на шаговых двигателях нужно два драйвера.

Число ножек ардуино отведенных под управление шаговыми двигателями составляет 8. В платформе с коллекторными моторами достаточно 4.

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

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

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

Последнее. Хранение литиевых аккумуляторов. Элементы 18650 нужно хранить в специальных пластиковых контейнерах. Это защитит их от механических повреждений и короткого замыкания.


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


И всё это лучше держать подальше от легковоспламеняющихся вещей.

Соблюдайте технику безопасности. Берегите себя и своих близких.