Створення власної бібліотеки керування двигуном постійного струму

Серія-статей: Ардуїно, використання двигунів постійного струму #4

Ми створили клас для керування двигуном постійного струму. Але якщо ми хочемо застосовувати його в кількох проектах, то для кожного потрібно буде скопіювати один і той же код Тому є сенс виділити весь код, що повторюється, в окрему бібліотеку, яку будемо підключати так само, як і стандартні бібліотеки Arduino (аналогічно, як ми зробили це для {{a|https://techi-news.com/%D0%90%D1%80%D0%B4%D1%83%D1%97%D0%BD%D0%BE/%D0%A1%D1%82%D0%B2%D0%BE%D1%80%D0%B5%D0%BD%D0%BD%D1%8F_%D0%B2%D0%BB%D0%B0%D1%81%D0%BD%D0%BE%D1%97_%D0%B1%D1%96%D0%B1%D0%BB%D1%96%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D1%96%D0%BD%D0%BD%D1%8F_%D1%81%D0%B5%D1%80%D0%B2%D0%BE%D0%BF%D1%80%D0%B8%D0%B2%D0%BE%D0%B4%D0%BE%D0%BC|сервоприводів}).

Отже, заходимо до папки /libraries нашого середовища розробки Arduino, і бачимо 10-15 папок, кожна з яких відвіяє за стандартну бібліотеку Arduino. Створимо тут папку для нашої бібліотеки, наприклад MotorS (шлях до неї має виглядати приблизно як “/Arduino/libraries/MotorS/"). Усередині цієї папки створимо два файли: MotorS.h, MotorS.cpp. з++ або у звичайному текстовому редакторі з підсвічуванням синтаксису, наприклад, AkelPad.

Перший файл, MotorS.h – заголовний файл (від слова header file), тут описуватимуться сам клас, змінні та функції. При цьому тут мають лише список змінних і функцій та їх типів, без тіла самих функцій.

Скопіюємо у файл MotorS.h наш клас MotorClass, точніше лише змінні та назви функцій:

/* Користувальницька бібліотека управління сервоприводами, заголовковий файл */

#ifndef MotorS // Якщо бібліотека ще не була підключена

#define MotorS // Підключити її

#include "Arduino.h" // Використовуємо стандартну бібліотеку Arduino

class MotorClass

{

public:

byte pinE; // Номер цифрового виходу для управління швидкістю – повинен підтримувати ШІМ

byte pinI; // Номер цифрового виходу керувати напрямом обертання

boolean SpeedChanging; // Чи увімкнено режим прискорення двигуна (обробляється функцією UpdateSpeed())

unsigned long StartTimer; // Таймер для плавного запуску

int StartTimeStep; // Інтервал зміни потужності двигуна, мс

int StartPowerStep; // Один крок зміни потужності двигуна

int ReqPower; // До якого закінчення змінюватиметься потужність двигуна

int Power; // Потужність двигуна (0 - зупинка, 255 - повна потужність)

int Direction; // Напрямок обертання

MotorClass(int pE, int pI); // Конструктор класу. Перший аргумент – номер піна управління швидкістю, другий – напрямком

void RunMotor(int motorpower); // Задаємо швидко і напрямки обертання двигуна

// Негативне значення - обертання у зворотний бік

void SetSpeed(int newspeed); // Встановлюємо швидкість двигуна у відсотках максимуму.

void SetSpeed(int newspeed, int smooth); // Плавно змінюємо швидкість двигуна у відсотках від максимуму.

// Негативне значення - обертання у зворотний бік

// Плавність зміни регулюється значенням smooth (час на один крок зміни швидкості, мс)

void UpdateSpeed(); // Обробка дій, які мають проводитися із затримкою, зокрема плавної зміни швидкості

};

#endif

При створенні бібліотеки можна побачити деякі особливості:

Файл починається з директиви #ifndef ServoS, яка перевіряє, чи не було підключено цю бібліотеку раніше. Якщо ми ніде раніше її не підключали, то до програми буде додано код, що знаходиться між #define MotorS та #endif

Крім того ми визначаємо кілька функцій з одним ім'ям та різними аргументами. Це пов'язано з тим, що при використанні бібліотек виклик функції з меншою, ніж визначено кількістю аргументів призведе до помилок. Задати значення аргументів за умовчанням не вдасться, точніше для кожного випадку потрібно буде описати окрему функцію. Тому у нас по дві функції SetSpeed(int newspeed) та SetSpeed(int newspeed, int smooth)

Тепер залишилося розібратися із файлом MotorS.cpp. Тут знаходиться код для описаних у заголовному файлі функцій. При цьому нам потрібно вказувати, до якого класу відносяться функції, що викликаються. Оскільки в нашій бібліотеці використовується клас MotorClass, всі функції будуть ставитися до нього. У випадку конструктора, ім'я якого збігається з ім'ям класу, це буде виглядати як MotorClass:: MotorClass (), решта функцій – відповідно MotorClass::Ім'яФункції();

/* Користувальницька бібліотека управління сервоприводами */

#include "MotorS.h" // Підключаємо заголовний файл

MotorClass:: MotorClass (int pE, int pI) // Конструктор класу. Перший аргумент - номер піна управління швидкістю, другий - напрямом

{

pinE = pE; // Задаємо керуючі піни для швидкості

pinI = pI; // І напрямки обертання

pinMode (pinE, OUTPUT); // Задаємо роботу відповідних пінів як виходи

pinMode (pinI, OUTPUT);

Power = 0; // за умовчанням двигун стоїть

SpeedChanging=false; // За умовчанням двигун не пришвидшується

}

void MotorClass::RunMotor(int motorpower) // Задаємо швидкість і напрямки обертання двигуна

// Негативне значення - обертання у зворотний бік

{

Direction=(motorpower>0)?HIGH:LOW; // Якщо вказано позитивну швидкість - на вихід напрямку подається сигнал HIGH

digitalWrite(pinI,Direction); // для негативної – LOW

digitalWrite(pinE,abs(Power)); // Подаємо на вихід керування швидкістю сигнал, який відповідає потрібній швидкості

}

MotorClass::SetSpeed(int newspeed) // Встановлюємо швидкість двигуна у відсотках від максимуму.

{

Power=(int)newspeed/2.55; // Оскільки швидкість змінюється від 0 дл 100%, а потужність - в діапазоні від 0 до 255,

// обчислюємо необхідне значення потужності

RunMotor(Power);

}

MotorClass::SetSpeed(int newspeed, int smooth) // Плавно змінюємо швидкість двигуна у відсотках від максимуму.

// Негативне значення - обертання у зворотний бік

// Плавність зміни регулюється значенням smooth (час на один крок зміни швидкості, мс)

{

ReqPower=(int)newspeed/2.55; // Оскільки швидкість змінюється від 0 дл 100%, а потужність – у діапазоні від 0 до 255, обчислюємо потрібне значення

if (ReqPower>=Power) // У який бік змінюватиметься потужність?

StartPowerStep=1; // збільшуватись на 1 (1/255 від повної)

else

StartPowerStep=-1; // зменшуватись на 1 (1/255 від повної)

StartTimeStep=smooth;

StartTimer=millis(); // Починаємо відлік часу зміни швидкості

SpeedChanging=true; // встановлюємо режим зміни швидкості, для подальшої обробки функції UpdateSpeed()

}

void MotorClass::UpdateSpeed() // Обробка дій, які повинні проводитися із затримкою,

{

if (SpeedChanging) // Якщо встановлено режим зміни швидкості

if ((millis()-StartTimer)>= StartTimeStep) // Якщо з попередньої зміни швидкості пройшло більше часу, ніж задано

{

if (Power! = ReqPower) // Поки не досягли потрібної швидкості

{

Power+=StartPowerStep; // міняємо швидкість

RunMotor(Power); // даємо команду двигуну

StartTimer=millis(); // встановлюємо таймер для початку відліку для наступного зміни потужності

}

else // Якщо потрібна швидкість досягнута

SpeedChanging=false; // Вимикаємо режим зміни швидкості

}

}

Для використання нашої бібліотеки скористаємося попереднім прикладом, в якому ми підключали два двигуни:

Підключення двох двигунів постійного струму до Arduino через драйвер L298P для керування бібліотекою користувача}

У коді програми всю частину, яка відповідала за опис нашого класу MotorClass, замінимо на функцію підключення бібліотеки #include "MotorS.h". Розмір даних, що завантажуються в контролер, практично не зміниться (адже ми, фактично, додаємо код з бібліотеки до того, який відображається в полі редагування). Але працювати з такою програмою набагато простіше, адже не потрібно щоразу, коли ми хочемо керувати двигунами, копіювати всі керуючі змінні та функції.

/* Управління двигунами постійного струму користувальницькою бібліотекою з підтримкою плавної зміни швидкості */

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

MotorClass M1(5,4); // Перший двигун управляється виходами 5 і 4 (швидкість та напрямок відповідно)

MotorClass M2(6,7); // Другий двигун управляється виходами 6 та 7

void setup()

{

M1.SetSpeed(50); //Перший двигун - увімкнути на 50% швидкості

M1.SetSpeed(-100, 2); // Другий двигун - увімкнути на 100% швидкості плавно

}

void loop()

{

M1.UpdateSpeed(); // Обробити зміни швидкості першого двигуна

M2.UpdateSpeed(); // Обробити зміни швидкості другого двигуна

}

Результат роботи програми, порівняно із звичайним використанням класу, не змінився – перший двигун максимально швидко розженеться до половини максимальної швидкості, другий обертатиметься у зворотний бік, причому на розгін з нуля до максимуму у нього піде пів секунди.

Залишилося лише подбати про підсвічування створених нами функцій Arduino IDE. Для цього зробимо в папці з нашою бібліотекою файл keywords.txt (шлях до нього має виглядати приблизно як “/Arduino/libraries/MotorS/keywords.txt”) У цей файл запишемо назви нашого класу та його методу , помітивши їх «KEYWORD1 для імені класу та «KEYWORD2» для методів:

Помістимо туди інформацію про ключові слова, які потрібно підсвічувати:

# Підсвічування синтаксису для бібліотеки MotorS

MotorClass KEYWORD1

RunMotor KEYWORD2

SetSpeed KEYWORD2

UpdateSpeed KEYWORD2

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

Знову перезавантажимо Arduino IDE, тепер наш клас та його функції підсвічуються відповідним кольором:

Без keywords.txt:

Код керування двигунами за допомогою бібліотеки користувача без підсвічування синтаксису

За допомогою keywords.txt:

Код керування двигунами за допомогою бібліотеки користувача з правильно створеним файлом keywords.txt

Тепер код більш розбірливий, а використання власноруч створеної бібліотеки нічим не відрізняється від використання стандартних бібліотек

Еще:

Подключаем двигатель постоянного тока. Микросхема L298P (Arduino, использование двигателей постоянного тока #1)
Плавный пуск двигателя постоянного тока с использованием таймеров (Arduino, использование двигателей постоянного тока #2)
Создание класса для работы с двигателем постоянного тока (Arduino, использование двигателей постоянного тока #3)
Создание собственной библиотеки управления двигателем постоянного тока (Arduino, использование двигателей постоянного тока #4)