Сервопривід (відстежуючий привід) - є «автоматичним точним виконавцем», який отримує в режимі реального часу вхідне значення керуючого параметра і, ґрунтуючись на показаннях датчика, прагне створити і підтримувати задане значення на виході виконавчого елемента.
Як працює сервопривід
Роботу сервоприводу можна описати такою схемою зі зворотним зв’язком:
Сервопривод керується за допомогою імпульсів змінної тривалості. Для подачі імпульсів використовується сигнальний провід.
Параметрами імпульсів керування є їх мінімальна тривалість, максимальна тривалість і частота повторення. Через обмеження в обертанні сервоприводу, нейтральне положення визначається як стан, в якому сервопривід має однакові можливості обертання в обох напрямках. Важливо відзначити, що різні сервоприводи мають різні обмеження в своєму обертанні, але всі вони мають нейтральне положення, і це положення завжди знаходиться в районі тривалості імпульсу в 1,5 мс.
Кут повороту визначається тривалістю імпульсу, який подається через сигнальний провід кожні 20 мс - це раніше розглянута ШІМ. Наприклад, імпульс тривалістю 1,5 мс диктує мотору поворот в положення 90 градусів (нейтральне положення):
Коли сервопривід отримує команду на переміщення, він переміщається в це положення і утримує його. Якщо зовнішня сила діє на сервопривід, коли він утримує задане положення, то сервопривід буде чинити опір переміщенню з цього стану. Максимальна величина сили, яку може витримувати сервопривід, характеризує обертовий момент сервоприводу. Однак, сервопривід не назавжди утримує свій стан, імпульси позиціонування повинні повторюватися, інформуючи сервопривід про збереження положення.
Керування сервоприводом за допомогою програмно сформованого ШІМ
Від сервопривода іде шлейф з трьох проводів:
червоний – живлення – підключається до контакту 5 В (вивід 2 – для малопотужних сервоприводів) або безпосередньо до джерела живлення;
коричневий або чорний – земля GND (вивід 6 RPi);
жовтий або білий – сигнал; підключимо до виводу 11 (GPIO17).
Зазвичай сервоприводи використовують живлення 5 В. Малопотужний сервопривід можна живити від Raspberry Pi. Але якщо привід споживає досить великий струм, або треба підключити кілька сервоприводів, краще не навантажувати порти Raspberry Pi, а використати окреме джерело живлення. Нагадаємо позначення виводів GPIO:
Для встановлення сервоприводу в нейтральну положення, необхідно подати високий сигнал тривалістю 1,5 мс, в 0 градусів – 0,5 мс, в 180 градусів – 2,5 мс.
Тепер, подаючи на серво імпульси різної довжини, ми можемо змінювати його положення.
Для програмного керування сервоприводом напишемо сценарій servo.py, код якого наведений у прикладі 1:
nano servo.py
Приклад 1 – Керування сервоприводом програмно
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(17,GPIO.OUT)
p=GPIO.PWM(17,50)
p.start(7.5)
try:
while True:
p.ChangeDutyCycle(7.5)
print("Left")
time.sleep(1)
p.ChangeDutyCycle(12.5)
print("Center")
time.sleep(1)
p.ChangeDutyCycle(2.5)
print("Right")
time.sleep(1)
except KeyboardInterrupt:
p.stop()
GPIO.cleanup()
Запустимо servo.py:
python3 ./servo.py
Автор програми спеціально вставив функції print в код. Наявність цих функцій створює проблему нестабільності програмно сформованого ШІМ. Сервопривід НЕ фіксується в заданому положенні і смикається. Якщо видалити функцію print, то проблема зменшиться або навіть зовсім зникне.
Керування сервоприводом за допомогою ШІМ, сформованого через DMA
RPIO.PWM забезпечує ШІМ через DMA (direct memory access – прямий доступ до пам’яті) для Raspberry Pi, використовуючи вбудований модуль PWM для напів-апаратної ШІМ з точністю до 1 мкс.
З RPIO.PWM ви можете використовувати будь-який з 15 DMA-каналів і будь-яку кількість виводів GPIO для кожного каналу. Оскільки ШІМ здійснюється через DMA, то RPIO.PWM практично не використовує ресурси центрального процесора і може генерувати стабільні імпульси з дуже високою роздільною здатністю. RPIO.PWM реалізований на C, але його можна використовувати на Python за допомогою наданої обгортки.
RPIO.PWM надає методи низького рівня для ручного контролю всім, а також допоміжні класи, які спрощують ШІМ для певних використань, наприклад, RPIO.PWM.Servo. Для цього модуля, поки що, підтримується тільки BCM GPIO нумерація.
Встановлюємо RPIO, якщо не встановлено:
Спочатку запускаємо команду:
sudo apt-get install python-dev
sudo apt-get install python-setuptools
sudo easy_install -U RPIO
Ви також можете отримати RPIO з репозиторію Github, який, як правило, на крок попереду pypi:
git clone https://github.com/metachris/RPIO.git
cd RPIO
sudo python setup.py install
Або з Github, але без Git:
curl -L https://github.com/metachris/RPIO/archive/master.tar.gz | tar -xz
cd RPIO-master
sudo python setup.py install
Приклад 2 - Використання PWM.Servo
Час субциклу (періоду) за замовчуванням 20 мс і ширина імпульсу за замовчуванням збільшується з кроком 10 мкс:
from RPIO import PWM
servo = PWM.Servo()
# Встановити серво на GPIO17 до 1200 μs (1.2 ms)
servo.set_servo(17, 1200)
# Встановити серво на GPIO17 до 2000 μs (2 ms)
servo.set_servo(17, 2000)
# Зупинити серво на GPIO17
servo.stop_servo(17)
Приклад 3 - Використання низькорівневих методів ШІМ
from RPIO import PWM
# Встановлення PWM і каналу DMA 0
PWM.setup()
PWM.init_channel(0)
# Додавання деяких імпульсів до субциклу
PWM.add_channel_pulse(0, 17, 0, 50)
PWM.add_channel_pulse(0, 17, 100, 50)
# Зупинка PWM для вказаного GPIO на каналі 0
PWM.clear_channel_gpio(0, 17)
# Зупинка всіх PWM і активності DMA
PWM.cleanup()
Приклад 4 – Програма керування серводвигуном через DMA
Напишемо сценарій servo_dma.py:
nano ./servo_dma.py
Текст сценарію:
import time
from RPIO import PWM
servo = PWM.Servo()
# Встановити servo на GPIO17 до 900 мкс (0.9 мс)
servo.set_servo(17, 900)
# Встановити servo на GPIO17 до 2000 мкс (2.0 мс)
#servo.set_servo(17, 2000)
try:
while True:
servo.set_servo(17, 750)
print("Left")
time.sleep(1)
servo.set_servo(17, 1500)
print("Center")
time.sleep(1)
print("Right")
servo.set_servo(17, 2500)
time.sleep(1)
except KeyboardInterrupt:
# Clear servo on GPIO17
servo.stop_servo(17)
Запустимо сценарій:
python ./servo_dma.py
Теперь сервопривід повинен працювати стабільно. Таким чином, для керування сервоприводами про програмну ШІМ бажано взагалі забути.
Детальніше про використання класу Servo і різних функцій можете прочитати за посиланням.
На відео нижче можете побачити різницю між різними способами генерування ШІМ сигналу:
16-канальний драйвер для сервоприводів від Adafruit
Для керування одночасно багатьма сервоприводами використовують спеціальні плати, наприклад, такий модуль:
Дана плата – ідеальне рішення для керування маніпулятором робота, бо використовується протокол I2C і забезпечує керування через 16 каналів. Серед інших технічних характеристик: частота 40-1000 Гц., роздільна здатність 12 біт, напруга постійного струму для живлення сенсорів 5-10 В.
Cтворимо просте програмне забезпечення, яке дозволить Raspberry Pi працювати з зображеною вище платою драйвера, керуючи кутом повороту деякого пристрою.
Установка програмного забезпечення та налаштування I2C
Почнемо зі звичайних рядків 'apt-get'. Просто введіть наступні команди для того, щоб завантажити і встановити необхідне програмне забезпечення:
sudo apt-get update
sudo apt-get install python-smbus i2c-tools git
sudo apt-get install build-essential python-dev
cd ~
git clone https://github.com/adafruit/Adafruit_Python_PCA9685.git
cd Adafruit_Python_PCA9685
sudo python setup.py install
За замовчуванням модулі I2C знаходяться в чорному списку. Щоб змінити це, виконайте наступну команду:
sudo nano /etc/modprobe.d/raspi-blacklist.conf
... і закоментуйте наступні рядки, поставивши # перед кожним з них:
blacklist spi-bcm2708
blacklist i2c-bcm2708
Збережіть зміни з Ctrl+O, потім натисніть Enter і вийдіть за допомогою Ctrl+X. Також необхідно додати наступні два рядки в /etc/modules:
i2c-dev
i2c-bcm2708
І, нарешті, запустимо sudo poweroff, щоб вимкнути Raspberry Pi.
Під’єднання контролера сервоприводу
Під’єднаємо контролер сервоприводу, як показано на схемі нижче. Дуже важливо, щоб все живлення було від'єднане в процесі налаштування. Крім того, необхідно переконатися, що Raspberry Pi зорієнтована правильно. Вивід OE на платі Adafruit означає Output Enable і має активним низький рівень, тобто, вихід включений, коли сигнал 0 В. Саме тому ми підключили його до землі. Вивід VCC на платі Adafruit повинен бути підключений до 3,3 В від Raspberry Pi, а живлення сервоприводу посередині плати - до 5 В. Живлення RPi повинен бути стстабільним, а сервоприводи часто викликають падіння напруги, тому може бути необхідне друге джерело живлення.
Перевірка з'єднання з контролером сервоприводу
Використаємо програму з назвою i2cdetect, щоб виявити контролер сервоприводу. Якщо використовуєте старий RPi, то номер шини I2C рівний 0, а в інших випадках номер шини I2C рівний 1. Введіть:
sudo i2cdetect -y 1
де 1 - номер шини I2C.
Ви повинні побачити результат, схожий на той, що на зображенні:
Спробуйте іншу шину I2C і, якщо не виявлений пристрій, то це, швидше за все, ви щось неправильно підключили.
Змініть каталог на той, в який git-клонували код Adafruit RPi (ви, ймовірно, в /home/pi). Для цього виконайте наступні команди:
cd Adafruit_Python_PCA9685
cd Adafruit_PWM_Servo_Driver
sudo python2 Servo_Example.py
Якщо сервопривід підключений до каналу 0 плати Adafruit, то він повинен почати рухатися між його мінімальним і максимальним положеннями.
Як працює плата Adafruit
Якщо відкриєте код Servo_Example.py в nano, то побачите, що він не такий вже й великий. Це тому, що плата Adafruit робить всю важку роботу і RPi просто говорить, що робити. Плата Adafruit потрібна тому, що сервопривід вимагає дуже точних широтно-імпульсної модуляції сигналів, щоб встановити необхідне положення. Це дуже важко зробити на Pi, тому що там відбувається багато інших речей.
Якщо подивитися на дві осциллограми, то можна побачити, що посилає плата Adafruit сервоприводу. Різниця в робочому циклі (відсоток часу, коли сигнал має високий рівень) між мінімальним і максимальним положеннями положення становить всього приблизно 10 відсотків.
Виконуємо код
Помістіть код сценарію Servo_VolumeControl.py в той ж каталог, що і приклад коду Adafruit і запустіть його з
sudo python2 Servo_VolumeControl.py
Сервопривод повинен обертатися вправо при натисканні на стрілку вгору і повернутися вліво при натисканні на стрілку вниз.
Лістинг коду Servo_VolumeControl.py:
import curses
from Adafruit_PWM_Servo_Driver import PWM
# Ініціалізувати пристрій PWM, використовуючи адресу за замовчуванням
pwm = PWM(0x40, debug=False)
servoMin = 150 # Мінімальна довжина імпульсу з 4096
servoMax = 600 # Максимальна довжина імпульсу з 4096
maxDegree = 60 # Градуси, на які ваш сервопривід може обертатися
degIncrease = 2 # На скільки градусів збільшувати щоразу
pwm.setPWMFreq(60) # Встановлення частоти PWM 60 Гц
def setDegree(channel, d):
degreePulse = servoMin
degreePulse += int((servoMax - servoMin) / maxDegree) * d
pwm.setPWM(channel, 0, degreePulse)
# Налаштування для керування
scr = curses.initscr()
curses.cbreak()
scr.keypad(1)
scr.addstr(0, 0, "Servo Control")
scr.addstr(1, 0, "UP to increase")
scr.addstr(2, 0, "DOWN to decrease")
scr.addstr(3, 0, "q to quit")
scr.refresh()
degree = 60 # Запуск з найменшого значення
setDegree(0, degree)
key = ''
while key != ord('q'):
key = scr.getch()
if key == curses.KEY_DOWN:
degree += degIncrease
if degree > maxDegree:
degree = maxDegree
setDegree(0, degree)
elif key == curses.KEY_UP:
degree -= degIncrease
if degree < 0:
degree = 0
setDegree(0, degree)
curses.endwin()