Створення власної бібліотеки управління сервоприводом
Серия-статей: Ардуіно, використання сервоприводів #6
Отже, заходимо до папки /libraries
нашого середовища розробки Arduino, і бачимо 10-15 папок, кожна з яких відвіяє за стандартну бібліотеку Arduino. Створимо тут папку для нашої бібліотеки, наприклад, ServoClass
. Усередині цієї папки створимо два файли: ServoS.h
, ServoS.cpp
. На жаль, середовище Arduino IDE не підтримує редагування файлів з роздільною здатністю, відмінною від .ino
. Тому редагувати бібліотеку доведеться або в іншому середовищі розробки, яке підтримує з ++ або у звичайному текстовому редакторі з підсвічуванням синтаксису, наприклад, AkelPad.
Перший файл, ServoS.h
– заголовний файл (від слова header file), тут описуватимуться сам клас, змінні та функції. При цьому тут мають лише список змінних і функцій та їх типів, без тіла самих функцій.
Скопіюємо у файл ServoS.h
наш клас ServoClass
, точніше лише змінні та назви функцій:
/* Користувальницька бібліотека управління сервоприводами */
#ifndef ServoS // Якщо бібліотека ще не була підключена
#define ServoS // Підключити її
#include "Arduino.h" // Використовуємо стандартну бібліотеку Arduino
#include "Servo.h" // Використовуємо стандартну бібліотеку управління сервоприводами
class ServoClass
{
public:
Servo serv; // Власне сам сервопривід, керований стандартною
// бібліотекою servo
int servPosition; // Поточна позиція сервоприводу, градусів
int posMax; // Максимально допустима межа переміщення сервоприводу, градусів
int posMin; // Мінімальна допустима межа переміщення сервоприводу, градусів
int posInit; // Вихідна позиція сервоприводу, градусів
// Змінні, які відповідають за переміщення
boolean move; // Чи повинен рухатися сервопривід зараз
int movePosition; // Позиція, яку має прийняти сервопривід, градуси
float moveSpeed; // Швидкість, з якою сервопривод повинен рухатися, об/хв
int moveIncrement; // Зміна положення за один інтервал часу, градусів
int moveInterval; // Інтервал між рухами для забезпечення швидкості, мілісекунди
unsigned long lastTimeCheck; // Час останнього руху сервоприводу, мс від початку роботи програми
ServoClass(); // Конструктор класу
void AttachServo (int pin); //Ініціалізація сервоприводу із зазначенням лише номери виходу для підключення
void AttachServo (int pin, int minpos, int maxpos, int initpos); //Ініціалізація сервоприводу із зазначенням мінімальної, максимальної та вихідної позиції
int PositionCheck(int movepos); // Перевірка, чи позиція попадає в заданий інтервал
void MoveTo (int movepos); // Подати команду на переміщення сервоприводу
void MoveTo (int movepos, float movespeed) ; // Подати команду на переміщення сервоприводу із зазначенням швидкості
void Update(); //Обробка переміщень
};
#endif
При створенні бібліотеки можна побачити деякі особливості:
Файл починається з директиви #ifndef ServoS
, яка перевіряє, чи не було підключено цю бібліотеку раніше. Якщо ми ніде раніше її не підключали, то до програми буде додано код, що знаходиться між #define ServoS
та #endif
Крім того ми визначаємо кілька функцій з одним ім'ям та різними аргументами. Це пов'язано з тим, що при використанні бібліотек виклик функції з меншою, ніж визначено кількістю аргументів призведе до помилок. Задати значення аргументів за умовчанням не вдасться, точніше для кожного випадку потрібно буде описати окрему функцію. Тому у нас по дві функції AttachServo
та MoveTo
Тепер залишилося розібратися з файлом ServoS.cpp
. Тут знаходиться код для описаних у заголовному файлі функцій. При цьому нам потрібно вказувати, до якого класу відносяться функції, що викликаються. Оскільки в нашій бібліотеці використовується клас ServoClass
, всі функції будуть ставитися до нього. У випадку конструктора, ім'я якого збігається з ім'ям класу, це буде виглядати як ServoClass::ServoClass()
, решта функцій – відповідно ServoClass::Ім'яФункції();
/* Користувальницька бібліотека управління сервоприводами */
#include "ServoS.h" // Підключаємо заголовний файл
ServoClass::ServoClass() // Конструктор класу
{
posMin = 0;
posMax = 180;
posInit = 0;
servPosition=0;
lastTimeCheck=millis();
}
servoClass::AttachServo (int pin) ////Ініціалізація сервоприводу із зазначенням тільки номери виходу для підключення
{
serv.attach(pin); // Підключаємо сервопривід до вказаного піна
posMin = 0; // Встановлюємо мінімальну позицію
posMax = 180; // Встановлюємо максимальну позицію
posInit = 0; // Встановлюємо вихідну позиціюservPosition = posInit; // Позиція сервоприводу повинна відповідати вихідному положенню
serv.write(servPosition); // Даємо команду змінити положення
}
servoClass::AttachServo (int pin, int minpos, int maxpos, int initpos) //Ініціалізація сервоприводу із зазначенням мінімальної, максимальної та вихідної позиції
{
serv.attach(pin); // Підключаємо сервопривід до вказаного піна
posMin = minpos; // Встановлюємо мінімальну позицію
posMax = maxpos; // Встановлюємо максимальну позицію
posInit = initpos; // Встановлюємо вихідну позицію
servPosition = posInit; // Позиція сервоприводу повинна відповідати вихідному положенню
serv.write(servPosition); // Даємо команду змінити положення
}
int ServoClass::PositionCheck(int movepos) // Перевірка, чи потрапляє позиція в заданий інтервал
{
int CheckedPos;
if (movepos<=posMin) // Якщо вказано більше значення, ніж максимальний
// межа переміщення
CheckedPos = posMin; // Рухатимемося тільки до цієї межі
else
if (movepos>=posMax) // Якщо вказано менше значення, ніж мінімальний
//Межа переміщення
CheckedPos = posMin; // Рухатимемося тільки до цієї межі
else // У будь-яких інших випадках - ми в допустимих для переміщення межах
CheckedPos =movepos; // Просто встановлюємо позицію, в яку має
return CheckedPos;
}
ServoClass::MoveTo (int movepos) // Якщо швидкість не вказана - просто даємо команду на переміщення сервоприводу
{
movePosition = PositionCheck(movepos); // Перевіряємо, чи ми виходимо за допустимі межі преміщення
serv.write(servPosition); // Даємо команду змінити положення
}
void ServoClass::MoveTo (int movepos, float movespeed) // Якщо швидкість вказана - організуємо плавне переміщення
{
movePosition = PositionCheck(movepos); // Перевіряємо, чи ми виходимо за допустимі межі преміщення
moveSpeed=movespeed; // Встановлюємо швидкість, з якою має переміщатися сервопривід
int Angle = abs (movePosition-servPosition); // На скільки має переміститися сервопривід
// незалежно від напрямку
if (movePosition >= servPosition) // Визначаємо, в який бік від поточного положення нам потрібно рухатися
moveIncrement=1; // Якщо вперед - додаватимемо один градус за один інтервал часу
else
moveIncrement=-1; // Якщо назад - то забирати
float RotationSpeed=moveSpeed*360/60; // Переводимо швидкість з оборотів за хвилину в градуси за секунду
moveInterval=(int)1000/RotationSpeed; // Обчислюємо інтервал між переміщеннями на градус.
move = true; // Даємо комнду почати плавне переміщення
}
ServoClass::Update () //// Обробка переміщень
{
if (move) // Якщо дана команда на переміщення
{
if ((millis() - lastTimeCheck)>= moveInterval) // перевіряємо, скільки минуло часу з останнього
//Дії та порівнюємо з потрібним нам інтервалом.
//Якщо часу пройшло більше - чинимо наступну дію
{
servPosition+=moveIncrement; // Змінюємо кут на раніше обчислене значення
serv.write(servPosition); // Посилаємо сервоприводу команду з новим кутом повороту
lastTimeCheck = millis (); // Оновлюємо лічильник часу, щоб наступний відлік часу почався з цього моменту
if (servPosition==movePosition) // Якщо ми досягли потрібної позиції-
move = false; // зупинити рух
}
}
}
Власне, зі створенням бібліотеки ми закінчили, залишилося підключити її до нашої програми. Для цього просто замінимо опис нашого класу з попереднього прикладу на "#include "ServoS.h"
" Підключимо два сервоприводи і завантажимо скетч:
#include "Servo.h" // Підключаємо бібліотеку для роботи із сервоприводом
#include "ServoS.h" // Підключаємо користувальницьку бібліотеку для роботи з сервоприводом
ServoClass serv1;
ServoClass serv2;
void setup()
{
serv1.AttachServo(2); // Перший сервопривід підключений до другого піну
// Стандартні межі переміщення від 0 до 180 градусів
// Стандартне вихідне положення 0 градусів
serv2.AttachServo(3, 20, 160, 90); // Другий сервопривід підключений до третього піна
// Межі переміщення від 20 до 160 градусів
// Початкове становище - 90 градусів
serv1.MoveTo(20); // Переміщаємо перший сервопривід у положення 20 градусів
serv2.MoveTo(150, 0.5); // Переміщаємо другий сервопривід у положення 150 градусів зі швидкістю 0.5 обороту за хвилину
}
void loop()
{
serv1.Update(); // Обробляємо переміщення першого сервоприводу
serv2.Update(); // Обробляємо переміщення другого сервоприводу
}
Результат роботи програми не змінився - перший сервопривід займе вказане положення відразу, а другий повертатиметься досить повільно (його вихідне положення 90 градусів, для переміщення в положення 150 градусів потрібно повернутися на 60 градусів. Швидкість 0.5 обороту в хвилину відповідає 3 градуси в секунду, т .е переміщення займе 20 секунд).
Залишилося оформити нашу бібліотеку для зручнішого використання. Якщо використовувати Arduino IDE, то функції стандартних бібліотек підсвічуються кольором, а для нашої бібліотеки – ні. Тому потрібно повідомити програму, які функції потрібно підсвічувати, для цього потрібно створити файл keywords.txt
у папці нашої бібліотеки
Помістимо туди інформацію про ключові слова, які потрібно підсвічувати:
# Підсвічування синтаксису для бібліотеки ServoS
ServoClass KEYWORD1
AttachServo KEYWORD2
PositionCheck KEYWORD2
MoveTo KEYWORD2
Update KEYWORD2
Слова, що позначені KEYWORD1 будуть підсвічені як тип даних, KEYWORD2 – як функції Між словом та його типом ставиться знак табуляції, між рядками – переклад рядка.
Знову перезавантажимо Arduino IDE, тепер наш клас та його функції підсвічуються відповідним кольором.