14 грудня 2016 р.

13. Драйвер двигунів

Вибір

Вибираючи плату з драйвером двигунів, ми зробили ще одну помилку. Здавалося би - що тут думати. Береш перший-ліпший оптимальний по ціні модуль - і двигуни їдуть. Але виявилося, що варто було подумати трохи грунтовніше.

Ми спокусилися на найдешевшу версію, виконану у вигляді шилда: Motor Drive Shield L293D For Arduino Duemilanove Mega UNO

Motor Drive Shield L293D For Arduino Duemilanove Mega UNO



Цей модуль робить рівно те, що має робити, але не більше. Його можна підключати як шилд зверху на Arduino UNO чи MEGA. Він може керувати чотирма двигунами постійного струму і двома сервомашинками. Нажаль, модуль повністю закриває всі гнізда UNO і не передбачає простого під'єднання навіть до тих, які ним не використовуються. Єдиний спосіб - припаювати провідники прямо до гребінки контактів на платі шилда.

Значно зручніше було би взяти менший варіант, який можна розмістити поряд з платою Arduino і під'єднати до потрібних портів провідниками: L293D Motor Drive Expansion Shield Dual H-Bridge For Arduino Duemilanove Mega UNO.
L293D Motor Drive Expansion Shield Dual H-Bridge For Arduino Duemilanove Mega UNO

Цей модуль може керувати лише двома двигунами, але і цього би нам було абсолютно достатньо.

"Люкс"-версією нашого шилда є 2 Channel Motor + 16 Channel Servo Expansion Board For Arduino UNO Smart Car Chassis Robot Arm.
2 Channel Motor + 16 Channel Servo Expansion Board For Arduino UNO


Він базується на цьому ж драйвері L293D, може керувати двома ходовими двигунами і 16-ма сервомашинками. Причому команди сервомашинкам передаються через протокол I2C. Тобто використавши 2 виходи Arduino ми отримуємо 16 повноцінних PWM виходів. Причому - ті два виходи Arduino не є втраченими. До них можна підключати й інші I2C пристрої. Такий шилд є ідеальним, якщо планується використання роботизованих рук та інших маніпуляторів такого типу.

І нарешті є ще один дуже цікавий варіант: DC Stepper Motor Shield V2 TB6612FNG PWN Drive Module For Arduino.
DC Stepper Motor Shield V2 TB6612FNG PWN Drive Module For Arduino

Скоріш за все, це клон шилда Adafruit Motor/Stepper/Servo Shield for Arduino v2. Якщо так - саме цей шилд мав би стати нашим чемпіоном. Крім гнізд для підключення інших шилдів зверху, на платі є площина з металізованими отворами на якій можна створити міні-макетну плату, і вмонтувати на неї наприклад MP3 модуль, чи підсилювач звуку, чи регістр зсуву для блимання діодами... Але основною особливістю є те, що всі двигуни і сервомашинки керуються виключно через протокол I2C і не займають жодного порта Arduino! Якби ми знали про такий шилд раніше - може і не довелося б переходити на MEGA…

Ну, але вже нехай. Будемо працювати з тим, що маємо. А ви - маєте шанс скористатися з нашого досвіду і зробити все краще та ефективніше.

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

Встановивши Arduino MEGA 2560 на шасі, ми взялися за наступну задачку - як підключити до нього два шилда, якщо на них не розпаяні гнізда на верхній площині.

Крім шилда драйвера двигунів у нас є ще ESP13 - Wi-Fi контролер, через який було реалізовано дистанційне керування. Це також наслідок еволюційного (agile?) способу проектування робота. Якби ми думали наперед, то скоріш за все би використали щось компактніше, типу: ESP8266 ESP-01S Remote Serial Port WIFI Transceiver Wireless Module.
ESP8266 ESP-01S Remote Serial Port WIFI Transceiver Wireless Module

Звісно ж, для правильних електронщиків, проблема відсутності гнізд на платі виглядає сміхотворною. Випаяти з одного шилда гребінку з контактами і замінили на правильну - скільки там тої роботи. Але нам, аматорам, було таке робити страшно. Припаяти контакти - то просто. А от перед тим акуратно випаяти стару гребінку і в процесі нічого не спалити, і не здути феном корисні деталі - то вже задоволення зовсім не те…


Вирішили, що шилд з драйвером двигунів будемо монтувати на Arduino, а ESP13 підключимо окремо через чотири провідники, які будуть припаяні до контактів на шилді драйвера двигунів (5V, GND, TX, RX).

В результаті вийшла ось така конструкція:



Зверніть увагу - живлення двигунів підключене від окремого батарейного блоку до спеціального гнізда на шилді біля  лівого нижнього кута. При бажанні можна то живлення використати і для самого Arduino. Але про це -  окрема розповідь.

На шилді ESP13 знайшовся дуже зручний порт UART куди поряд виведено всі 4 контакти, необхідні для його роботи. Саме на нього ми і націлили чотирьохконтактний штекер, випаяний із непотрібної плати:

Сам ESP13 винесли подалі від іншої електроніки і прикрутили болтами під верхню кришку робота - так він краще ловить радіохвилі.



Останній штрих - підключили звуковий динамік прямо в один з портів керування сервомашинкою на шилді драйвера двигуна. Для простоти схеми, автори шилда вивели виходи Arduino #9 та #10 напряму в гнізда керування сервомашинками. Тому, якщо підключити динамік між керуючим контактом сервомашинки і GND, звук відтворюватиметься без жодних проблем.

Гарний детальний опис особливостей роботи з шилдом двигунів можна почитати тут: Мотор шилд для Arduino (рос.) або тут Подключение драйвера двигателей Motor Shield L293D к плате Arduino (рос.).

Робота з двигунами через драйвер вимагає зміни в програмному коді.  Замість прямих маніпуляцій з виходами Arduino, зручніше використати готову бібліотеку звідси: https://github.com/adafruit/Adafruit-Motor-Shield-library

Тепер наш клас для керування двигунами виглядатиме трохи простіше:

// підключаємо бібліотеку керування двигунами
#include "AFMotor.h"

// добре, що всі операції роботи з двигунами заховані в одному класі
// не мусимо вишуковувати шматки коду по всіх файлах
class RobotMotors: public TaskInterface {
private:
 // номери гнізд на шилді, 
 // до яких ми підключили свої двигуни
 const uint8_t leftDriveID = 3;
 const uint8_t rightDriveID = 4;

 // службові об'єкти для роботи з двигунами
 AF_DCMotor* leftMotor;
 AF_DCMotor* rightMotor;
...

}

// конструктор викликається автоматично при створенні об'єкта
RobotMotors::RobotMotors() {
...
 // створюємо об'єкти двигунів
 leftMotor = new AF_DCMotor(leftDriveID, MOTOR34_64KHZ);
 rightMotor = new AF_DCMotor(rightDriveID, MOTOR34_64KHZ);
}

// деструктор викликається автоматично 
// після закінчення роботи з об'єктом
// хоча навряд чи цей код колись буде реально виконуватися
// кнопка живлення вивільняє всю пам'ять швидко і надійно
RobotMotors::~RobotMotors() {
 // не забуваємо зупинити двигуни і
 // вивільнити пам'ять
 fullStop();
 delete leftMotor;
 delete rightMotor;
}

// набір стандартних функцій руху і поворотів
// відрізняються лише напрямком руху кожного двигуна
void RobotMotors::driveForward(uint8_t speed, uint16_t duration) {
     runDrives(speed, duration, FORWARD, FORWARD);
}
void RobotMotors::driveBackward(uint8_t speed, uint16_t duration) {
     runDrives(speed, duration, BACKWARD, BACKWARD);
}
void RobotMotors::turnRight(uint8_t speed, uint16_t duration) {
     runDrives(speed, duration, FORWARD, BACKWARD);
}
void RobotMotors::turnLeft(uint8_t speed, uint16_t duration) {
     runDrives(speed, duration, BACKWARD, FORWARD);
}

// цей метод власне і встановлює швидкість на напрямки обертання двигунів
void RobotMotors::runDrives(uint8_t speed, uint16_t duration,
                     uint8_t leftDirection, uint8_t rightDirection) {
 leftMotor->setSpeed(speed);
 rightMotor->setSpeed(speed);
 leftMotor->run(leftDirection);
 rightMotor->run(rightDirection);

 scheduleTimedTask(duration);
}

// повна зупинка двигунів
void RobotMotors::fullStop() {
 leftMotor->run(RELEASE);
 rightMotor->run(RELEASE);
}

Наш робот набув здатності їздити заднім ходом! І виконує повороти значно шустріше, бо працює тепер обидвома гусеницями. Та й виглядає ошатніше - розмістивши остаточно головні модулі, вдалося причепити верхній поверх та провести провідники акуратніше.

Наснупного разу поговоримо про те, як підібрати оптимальну систему живлення.



Немає коментарів:

Дописати коментар