Создание собственной библиотеки управления двигателем постоянного тока
Серия-статей: Arduino, использование двигателей постоянного тока #4
Серия-статей: Создание библиотек для Arduino #2
Итак, заходим в папку /libraries
нашей среды разработки Arduino, и видим 10-15 папок, каждая из которых отвеяает за стандартную библиотеку Arduino. Создадим здесь папку для нашей библиотеки, например MotorS
(путь к ней должен выглаядеть примерно как “/Arduino/libraries/MotorS/"). Внутри этой папки создадим два файла: MotorS.h
, MotorS.cpp
. К сожалению среда Arduino IDE не поддерживает редактирование файлов с разрешением, отличным от .ino
. Поэтому редактировать библиотеку придется либо в другой среде разработки, которая поддерживает с++ или в обычном текстовом редакторе с подсветкой синтаксиса, например 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)); // Подаем на выход управления скоростью сигнал, который соответствует нужной скорости
}
void MotorClass::SetSpeed(int newspeed) // Устанавливаем скорость двигателя в процентах от максимума.
{
Power=(int)newspeed/2.55; // Поскольку скорость меняется от 0 дл 100 %, а мощность - в диапазоне от 0 до 255,
// вычисляем необходимое значение мощности
RunMotor(Power);
}
void 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; // Выключаем режим изменения скорости
}
}
Для использования нашей библиотеки воспользуемся предыдущим примером, в котором мы подключали два двигателя:
В коде программы всю часть, которая отвечала за описание нашего класса 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
:
Теперь код более разборчив, а использование собственноручно созданной библиотеки ничем не отличается от использования стандартных библиотек