Raspberry Pi - PWM і Сервопривод
Raspberry Pi має декілька шляхів для реалізації PWM (Широтно-імпульсної модуляції). Ми розглянемо як реалізувати, PWM програмно, та задіємо для генерації PWM апаратні ресурси Raspberry Pi. Спочатку будемо змінювати яскравість світлодіода, а потім навчимося керувати сервоприводом.
Що таке PWM (ШІМ) ?
Широтно-імпульсна модуляція (ШІМ) - це імпульсний сигнал постійної частоти і змінної шпаруватості, тобто відношення тривалості імпульсу до періоду його проходження. За допомогою завдання шпаруватості (тривалості імпульсів) можна міняти середнє значення напруги на виході ШІМ.Програмна реалізація PWM
Підключимо світлодіода до GPIO23 як вказано на схемі:Напишемо скрипт pwm_soft.py:
nano ./pwm_soft.py
Текст скрипта:
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.OUT)
p = GPIO.PWM(23, 50) # channel=23 frequency=50Hz
p.start(0)
try:
while 1:
for dc in range(0, 101, 5):
p.ChangeDutyCycle(dc)
time.sleep(0.1)
for dc in range(100, -1, -5):
p.ChangeDutyCycle(dc)
time.sleep(0.1)
except KeyboardInterrupt:
pass
p.stop()
GPIO.cleanup()
Запустимо його:
python ./pwm_soft.py
Світлодіод буде плавно загоратися і плавно гаснути.
Програмна реалізація PWM дозволяє сформувати PWM сигнал на будь-кому виводі. У цьому прикладі ми використовуємо RPi.GPIO для програмної генерації PWM сигналу. А це означає, що витрачаються обчислювальні ресурси мікрокомп’ютера. Якщо мікрокомп’ютер буде відволікатися на інші задачі, PWM сигнал буде викривлятися і не буде стабільним. Це не принципово, якщо PWM застосовується для керування яскравістю світлодіода. Але може стати неприйнятним, коли PWM застосовується для формування керуючого сигналу. Наприклад, при керуванні сервоприводами програмна реалізація PWM не може стабільно утримувати сервоприводи у заданому положенні.
Raspberry Pi має технічну можливість використовувати апаратний ресурс для генерації PWM.
Генерація PWM сигналу завдяки апаратним ресурсам Raspberry Pi
Проект WiringPi - це бібліотека, яка містить утиліти для простого доступу до GPIO. Вона дозволяє налаштувати апаратні модулі для спеціальних виходів PWM. Встановлюємо wiringPi:sudo apt-get install git-core
git clone git://git.drogon.net/wiringPi
cd wiringPi
./build
cd ..
Підключимо світлодіод до GPIO18 як вказано на схемі:
Перший вихід PWM заведений на GPIO18, інші канали PWM задіяні на аудіо-виході. Виконаємо наступні команди для формування на GPIO18 PWM сигналу. Налаштовуємо перший канал PWM (GPIO18):
gpio mode 1 pwm
Задаємо шпаруватість від 0 до 1024:
gpio pwm 1 500
Світлодіод має світитися напівсили. Проекспериментуйте з PWM. Спробуйте задати наступні значення:
gpio pwm 1 10
gpio pwm 1 1023
Відключаємо PWM:
gpio unexport 1
або
gpio unexportall
Генерація апаратного PWM сигналу на Python
Щоб використовувати PWM у Python треба встановили WiringPi-Python:sudo apt-get install python-dev python-setuptools
git clone https://github.com/WiringPi/WiringPi-Python
cd WiringPi-Python
git submodule update --init
python setup.py install
cd ..
Створимо срипт pwm.py:
nano pwm.py
Текст скрипта:
import time
import wiringpi
# GPIO pin 12 = BCM pin 18 = wiringpi pin 1
led_pin = 1
wiringpi.wiringPiSetup()
wiringpi.pinMode(led_pin, 2)
wiringpi.pwmWrite(led_pin, 0)
def led(led_value):
wiringpi.pwmWrite(led_pin, led_value)
led(0)
while 1:
for dc in range(0, 1023, 5):
led(dc)
time.sleep(0.01)
for dc in range(1024, 0, -5):
led(dc)
time.sleep(0.01)
Запустимо його:
python ./pwm.py
Світлодіод буде плавно загоратися і плавно гаснути. Апаратна реалізація PWM забезпечує більш стабільний результат. Нажаль апаратний вихід у Raspberry Pi тільки один. Але існує ще пара методів генерування PWM. Через DMA, та використання зовнішнього PWM контролера. Ці методи розглянемо нижче для керування сервоприводами, оскільки на світлодіодах різниця не буде помітна.
Керування Сервоприводом
Про сервоприводи та характеристики сигналу управління я писав раніше у статті Управление сервоприводом (сервомашинкой) с помощью микроконтроллера ATMega.Зазвичай сервоприводи використовують живлення 5В. Малопотужний сервопривід можна живити від Raspberry Pi. Але якщо привід споживає досить великий струм, або Вам потрібно підключити декілька сервомашинок, краще не навантажувати Raspberry Pi і використовувати окреме джерело живлення. Схема під’єднання сервопривода:
Керування сервоприводом за допомогою програмно сформованого PWM
Спочатку спробуємо формувати PWM для керування сервоприводом програмно. Cтворимо скрипт servo.py:nano servo.py
Текст скрипта:
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:
python ./servo.py
Я навмисно вставив функції print у код. Наявність цих функцій виявляє описану раніше проблему нестабільності програмно сформованого PWM. Сервомашинка не фіксується у заданому положенні і смикається. Якщо видалити інструкції print, проблема зменшується або взагалі зникає.
Керування сервоприводом за допомогою PWM, сформованого через DMA
Встановлюємо RPIO:apt-get install python-setuptools
easy_install -U RPIO
Створимо срипт servo_dma.py:
nano ./servo_dma.py
Текст скрипта:
import time
from RPIO import PWM
servo = PWM.Servo()
# Set servo on GPIO17 to 900.s (0.9ms)
servo.set_servo(17, 900)
# Set servo on GPIO17 to 2000.s (2.0ms)
#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
Тепер сервопривід працює стабільно. Тобто, для керування сервоприводами про програмний PWM бажано взагалі забути.
Подробиці використання RPIO читайте тут: http://pythonhosted.org/RPIO/pwm_py.html#examples
На цьому відео видно різницю між різними способами генерації PWM сигналу:
Servoblaster
Існує проект Servoblaster, який теж працює через DMA. За допомогою нього можна керувати до 8 сервоприводами. Servoblaster встановлюється як демон і дозволяє керувати сервоприводами через файли пристроїв. Тобто, керувати сервами можна через файлову систему. Це дозволяє керувати сервами використовуючи будь-яку мову програмування або з командного рядка і не потребує встановлення додаткових модулів таких як RPIO, котрий ми встановлювали раніше для Python.Встановлюємо Servoblaster:
git clone http://github.com/richardghirst/PiBits.git
cd PiBits/ServoBlaster/user
make
sudo make install
Перевіряємо чи Servoblaster встановлено:
ls /dev | grep servoblaster
Маємо побачити:
servoblaster
servoblaster-cfg
Можна переглянути конфіг Servoblaster-а:
cat /dev/servoblaster-cfg
Виводи на які можна підключати сервоприводи наведені у наступній таблиці:
Servo number | GPIO number | Pin in P1 header |
---|---|---|
0 | 4 | P1-7 |
1 | 17 | P1-11 |
2 | 18 | P1-12 |
3 | 21/27 * | P1-13 |
4 | 22 | P1-15 |
5 | 23 | P1-16 |
6 | 24 | P1-18 |
7 | 25 | P1-22 |
Допустимі значення положення залежать від вашого сервоприводу. У більшості вони лежать у діапазоні від 80 до 249. Напишемо наступний срипт для керування сервою:
nano ./servo_blaster.py
Текст скрипта:
import time
# Servo Channel 1 => GPIO 17
servoChannel = 1
def setServo(servoChannel, position):
servoStr ="%u=%u" % (servoChannel, position)
with open("/dev/servoblaster", "wb") as f:
f.write(servoStr)
if __name__ == `__main__`:
val = 50
direction = 1
while True:
#print val
setServo(servoChannel, val)
time.sleep(.01)
if val == 249:
direction -= 1
elif val == 50:
direction = 1
val += direction
Запустимо його:
python ./servo_blaster.py
Є одна особливість у Servoblaster. Поки він запущений, він займає 8 вказаних в таблиці виходів і під інші цілі ви їх вже не зможете задіяти. Спробуйте запустити раніше написані скрипти:
python ./servo.py
python ./servo_dma.py
Сервомашинка не працює як слід.
Спробуємо зупинити демон Servoblaster і повторити спробу. Зупиняємо Servoblaster за допомогою команди:
sudo killall servod
Перевіряємо чи нема тепер servod у запущених процесах:
ps ax | grep servod
Повторюємо запуск скриптів:
python ./servo.py
python ./servo_dma.py
Все працює як слід. Запускаємо servod командою:
/usr/local/sbin/servod --idle-timeout=2000
Виникає питання: а що робити, якщо треба задіяти лише декілька каналів, а не всі 8? Servoblaster можна конфігурувати завдяки наступним опціям:
--pcm tells servod to use PCM rather than PWM hardware to implement delays --idle-timeout=Nms tells servod to stop sending servo pulses for a given output N milliseconds after the last update --cycle-time=Nus Control pulse cycle time in microseconds, default 20000us --step-size=Nus Pulse width increment step size in microseconds, default 10us --min={N|Nus|N%} specifies the minimum allowed pulse width, default 50 steps or 500us --max={N|Nus|N%} specifies the maximum allowed pulse width, default 250 steps or 2500us --invert Inverts outputs --dma-chan=N tells servod which dma channel to use, default 14 --p1pins=<list> tells servod which pins on the P1 header to use --p5pins=<list> tells servod which pins on the P5 header to use
Зараз нас цікавить опція --p1pins. Зупинимо Servoblaster:
sudo killall servod
Та запустимо з новими опціями:
/usr/local/sbin/servod --idle-timeout=2000 --p1pins=11
Тепер Servoblaster займатиме одну ногу P1-11 (GPIO17). Перевірити це можна переглянувши конфіг:
cat /dev/servoblaster-cfg
Якщо перезавантажити Raspbery Pi, Servoblaster знову буде працювати з початковими опціями. Для того, щоб при старті системи Servoblaster запускався з Вашими налаштуваннями, вкажіть їх у файлі /etc/init.d/servoblaster
Ви можете прочитати детальніше про Servoblaster тут: https://github.com/richardghirst/PiBits/tree/master/ServoBlaster
Деінсталяція Servoblaster:
sudo killall servod
cd PiBits/ServoBlaster/user
make uninstall
Adafruit 16-channel servo driver
Якщо Вам потрібно керувати надзвичайною кількістю сервоприводів, доречно використовувати багатоканальний зовнішній PWM контролер. Наприклад Adafruit 16-channel servo driver, або його аналоги. Ця плата підключається до Raspberry Pi по інтерфейсу I2C і може одночасно керувати 16-ма сервоприводами. Детально про цей пристрій: PWM контролер на базе микросхемы PCA9685Успіхів!
Дивись також:
- Raspberry Pi — що це таке?
- Raspberry Pi — GPIO
- Raspberry Pi — UART
- Raspberry Pi — FT232
- Raspberry Pi — PWM і Сервопривод
- Raspberry Pi — DHT11
- Raspberry Pi - FM Transmitter
- Прошивка AVR мікроконтролерів за допомогою Raspberry Pi
- Raspberry Pi — LCD display 1602
- Raspberry Pi — WiFi
- Raspberry-Pi — I2C (TWI)
- Raspberry Pi - DS18B20
- Raspberry Pi Camera
- nRF24L01+ ATMEGA + Raspberry Pi
- BMP180 + Raspberry Pi + WH1602
- Wi-Fi Метео станція
- Raspbian. Apache + PHP + Python + MySQL
- Встановлюємо Raspbian на Raspberry Pi без клавіатури та монітору
- IR-дистанційне керування. Використання LIRC у Python
- Raspberry Pi. Raspbian. Відправлення пошти через аккаунт Gmail
- Neoway M590 – GSM/GPRS modem
- MPU-6050 – гіроскоп – акселерометр
- HMC5883L Магнітометр
- PWM контролер з інтерфейсом I2С на базі мікросхеми PCA9685
- Метеостанція на Raspberry Pi своїми руками
- Raspberry Pi. Live-stream video
Було б непогано, якщо у статті було відео роботи.
Дякую за зауваження. Відео обов`язково додам.
Добавив відео у статтю.
Доречі, підкажіть, будь-ласка, чим обумовлено вибір мови Python для реалізації керування ШІМ? Цікавлюсь, оскільки стою перед вибором на чому писати програми під CubieBoard (аналог Raspberry, але не таке велике комюніті).
Python дуже потужний і популярний. На ньому можна писати скрипти з графічним інтерфейсом. До тогож у Respbian він вже встановлений. Якщо не потрібна супершвидкість Python - саме те. Для іншого краще C. Доречі, треба буде добавити приклади на С.
Саме цікаве про pca9685 Ви і не розкрили
Недавні записи
- Text to speech. Українська мова
- LCD Display ST7567S (IIC)
- Розпізнавання мови (Speech recognition)
- Selenium
- Комп'ютерний зір (Computer Vision)
- Деякі думки про точність вимірювань в електроприводі
- Датчики Холла 120/60 градусів
- Модуль драйверів напівмосту IGBT транзисторів
- Драйвер IGBT транзисторів на A316J
- AS5600. Варіант встановлення на BLDC мотор
Tags
docker sensors rtc led timer wifi remap sms css websocket mongodb bme280 rfid bluetooth esp8266 nodemcu bkp piezo bmp280 i2c mpu-6050 encoder examples avr brushless ngnix nvic displays bldc java-script pmsm barometer pwm lcd ethernet stm32 raspberry-pi capture usart gpio exti atmega meteo solar smd dma adc eeprom eb-500 flask python ssd1306 uart options flash mpx4115a html gps st-link 3d-printer servo dc-dc foc git books battery hih-4000 watchdog dht11 web tim programmator ssd1331 mpu-9250 usb rs-232 motor max1674 soldering
Архіви