Створення класу для роботи з двигуном постійного струму
Серія-статей: Ардуїно, використання двигунів постійного струму #3
Зберемо схему з двох двигунів:
Створимо клас MotorClass
і додамо до нього пермінні для поточного стану двигуна (швидкість та напрямок обертання). Крім того, створимо змінні, які будуть використовуватися при плавній зміні швидкості.
У нашого класу буде кілька методів:
MotorClass(pE, pI)
– конструктор класу, тут ми будемо вказувати, якими виходами керуватимемо двигуном
RunMotor(motorpower)
- змінюємо внутрішні змінні (потужність, напрямок) і безпосередньо керуємо двигуном.
SetSpeed(newspeed)
– встановлюємо нову швидкість. Потужність змінюється в діапазоні 0.255, що не завжди зручно. Тому задаватимемо швидкість у % від максимуму
SetSpeed(newspeed, smooth)
– встановлюємо нову швидкість, робимо це не стразу, а плавно – встановлюємо відповідні змінні, а безпосередньо швидкість змінюватиметься функцією UpdateSpeed()
UpdateSpeed()
– тут перевірятиметься тимчасовий інтервал та змінюватиметься швидкість, якщо попереднім методом були встановлені відповідні змінні. Поміщаємо цю функцію в loop()
Ось що в нас вийшло:
/* Користувальницький клас управління двигунами постійного струму з підтримкою плавної зміни швидкості */
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) // Конструктор класу. Перший аргумент – номер піна управління швидкістю, другий – напрямком
{
pinE = pE; // Задаємо керуючі піни для швидкості
pinI = pI; // І напрямки обертання
pinMode (pinE, OUTPUT); // Задаємо роботу відповідних пінів як виходи
pinMode (pinI, OUTPUT);
Power = 0; // за умовчанням двигун стоїть
SpeedChanging=false; // За умовчанням двигун не пришвидшується
}
void RunMotor(int motorpower) // Задаємо швидкість і напрямки обертання двигуна
// Негативне значення - обертання у зворотний бік
{
Direction=(motorpower>0)?HIGH:LOW; // Якщо вказано позитивну швидкість - на вихід напрямку подається сигнал HIGH
digitalWrite(pinI,Direction); // для негативної – LOW
digitalWrite(pinE,abs(Power)); // Подаємо на вихід керування швидкістю сигнал, який відповідає потрібній швидкості
}
setSpeed (int newspeed) // Встановлюємо швидкість двигуна у відсотках від максимуму.
{
Power=(int)newspeed/2.55; // Оскільки швидкість змінюється від 0 дл 100%, а потужність - в діапазоні від 0 до 255,
// обчислюємо необхідне значення потужності
RunMotor(Power);
}
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()
}
UpdateSpeed()
{
if (SpeedChanging) // Якщо встановлено режим зміни швидкості
if ((millis()-StartTimer)>= StartTimeStep) // Якщо з попередньої зміни швидкості пройшло більше часу, ніж задано
{
if (Power! = ReqPower) // Поки не досягли потрібної швидкості
{
Power+=StartPowerStep; // міняємо швидкість
RunMotor(Power); // даємо команду двигуну
StartTimer=millis(); // встановлюємо таймер для початку відліку для наступного зміни потужності
}
else // Якщо потрібна швидкість досягнута
SpeedChanging=false; // Вимикаємо режим зміни швидкості
}
}
};
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(); // Обробити зміни швидкості другого двигуна
}
При запуску програми перший двигун максимально швидко розженеться до половини максимальної швидкості. А ось другий буде обертатися у зворотний бік, причому на розгін з нуля до максимуму у нього піде пів секунди (255 кроків зміни через 2мс). Управління двигунами незалежне, причому додавання ще кількох двигунів не викличе труднощів. На нашому motor-shield немає більше висновків для підключення моторів, але нам ніщо не заважає використовувати два однакових (єдине обмеження - ззовні контролера можна встановити тільки один, другий потрібно буде підключати проводами до відповідних виходів. Але для таких випадків існують чотириканальні motor-shield, в яких використовуються дві та більше мікромхеми L298P:
Така плата може керувати чотирма двигунами постійного струму, тобто можна, наприклад, зробити повністю незалежне управління кожного колеса чотириколісного робота. Єдиний недолік-у такому варіанті використовуються практично всі цифрові виходи звичайної плати UNO. Але ця проблема вирішується або використанням більш функціональної плати (наприклад Arduino MEGA з 54 цифровими виходами) або підключенням motor-shielda через L2P.