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

Серия-статей: Arduino, использование сервоприводов #6

Серия-статей: Создание библиотек для Arduino #1

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

Итак, заходим в папку /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();

}

void ServoClass::AttachServo (int pin) ////Инициализация сервопривода с указанием только номеры выхода для подключения

{

serv.attach(pin); // Подключаем сервопривод к указанному пину

posMin= 0; // Устанавливаем минимальную позицию

posMax= 180; // Устанавливаем максимальную позицию

posInit= 0; // Устанавливаем исходную позицию

servPosition= posInit; // Позиция сервопривода должна сответствовать исходному положению

serv.write(servPosition); // Даем команду изменить положение

}

void 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;

}

void 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; // Даем комнду начать плавное перемещение

}

void ServoClass::Update () ////Обработка перемещений

{

if (move) //Если дана команда на перемещение

{

if ((millis() - lastTimeCheck)>= moveInterval) // проверяем, сколько прошло времени с последнего

//действия и сравниваем с нужным нам интервалом.

//Если времени прошло больше – совершаем следующее действие

{

servPosition+=moveIncrement; // Изменяем угол на вычисленное ранее значение

serv.write(servPosition); // Посылаем сервоприводу команду с новым углом поворота

lastTimeCheck= millis(); // Обновляем счетчик времени, для того чтобы следующий отсчет времени начался с этого момента

if (servPosition==movePosition) // Если мы достигли нужной позиции-

move=false; // остановить движение

}

}

}

Если во время создания нашей библиотеке была включена среда Arduino IDE, то ее необходимо закрыть и заново перезапустить, поскольку она собирает данные о доступных библиотеках во время запуска и должна будет увидеть нашу новую библиотеку

Собственно с созданием библиотеки мы закончили, осталось подключить ее к нашей программе. Для этого просто заменим описание нашего класса из предыдущего примера на "#include "ServoS.h"" Подключим два сервопривода и загрузим скетч:

Схема подключения двух сервоприводов к Arduino с ограничением по углу поворота и управлением черз пользовательскую библиотеку

#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, теперь наш класс и его функции подсвечиваются соответствующим цветом

Еще:

Подключаем сервопривод к Arduino (Arduino, использование сервоприводов #1)
Создаем класс для управления сервоприводом (Arduino, использование сервоприводов #3)
Программное ограничение перемещения сервопривода (Arduino, использование сервоприводов #4)