сайт для палких паяльників
  • Facebook
  • Twitter
  • Google Plus
  • Add to favorites
  • Email
  • Print
  • RSS

Raspberry Pi имеет несколько путей реализации PWM (ШИМ) (Широтно-импульсной модуляции). Мы рассмотрим как реализовать, ШИМ программно, и задействуем для генерации ШИМ аппаратные ресурсы Raspberry Pi. Сначала будем менять яркость светодиода, а затем научимся управлять сервоприводом.

Что такое PWM (ШИМ)?

Широтно-импульсная модуляция (ШИМ) – это импульсный сигнал постоянной частоты и переменной скважности, то есть отношение длительности импульса к периоду его следования. С помощью задания скважности (длительности импульсов) можно менять среднее значение напряжения на выходе ШИМ. Подробнее о ШИМ читайте на Википедия.

PWM

Программная реализация ШИМ

Подключим светодиод к GPIO23 как указано на схеме:

Raspberry Pi & LED

Напишем скрипт 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

Светодиод будет плавно загораться и плавно гаснуть.

Программная реализация ШИМ позволяет сформировать ШИМ-сигнал на любому выводе. В этом примере мы используем RPi.GPIO для программной генерации ШИМ сигнала. А это значит, что тратятся вычислительные ресурсы микрокомпьютера. Если микрокомпьютер будет отвлекаться на другие задачи, ШИМ сигнал будет искажаться и не будет стабильным. Это не принципиально, если ШИМ применяется для управления яркостью светодиода. Но может стать неприемлемым, когда ШИМ применяется для формирования управляющего сигнала. Например, при управлении сервоприводами программная реализация ШИМ не может стабильно удерживать сервоприводы в заданном положении. Это заметно на видео ниже.

Raspberry Pi имеет техническую возможность использовать аппаратный ресурс для генерации ШИМ.

Генерирование ШИМ сигнала с использованием аппаратных ресурсов Raspberry Pi

Проект WiringPi – это библиотека, которая содержит утилиты для простого доступа к GPIO. Она позволяет настроить аппаратные модули для специальных выходов ШИМ. Установим wiringPi:

sudo apt-get install git-core
git clone git://git.drogon.net/wiringPi
cd wiringPi
./build
cd ..

Подключим светодиод к GPIO18 как указано на схеме:

Raspberry Pi & PWM

Первый выход ШИМ заведен на GPIO18, другие каналы ШИМ задействованы на аудио-выходе. Выполним следующие команды для формирования на GPIO18 ШИМ сигнала. Настраиваем первый канал PWM (GPIO18):

gpio mode 1 pwm

Задаем скважность от 0 до 1024:

gpio pwm 1 500

Светодиод должен светиться вполсилы. Поэкспериментируйте с ШИМ. Попробуйте задать следующие значения:

gpio pwm 1 10
gpio pwm 1 1023

Выключаем ШИМ:

gpio unexport 1

или

gpio unexportall

Генерирование аппаратного ШИМ сигнала на Python

Чтобы использовать ШИМ в 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

Светодиод будет плавно загораться и плавно гаснуть. Аппаратная реализация ШИМ обеспечивает более стабильный результат. К сожалению аппаратный выход в Raspberry Pi только один. Но существует еще пара методов генерирования ШИМ. Через DMA, и использование внешнего PWM контроллера (ШИМ контроллера). Эти методы рассмотрим ниже для управления сервоприводами, поскольку на светодиодах разница не будет заметна.

Управление сервоприводом

О сервоприводах и характеристиках управляющего сигнала я писал ранее в статье Управление сервоприводом (сервомашинкой) с помощью микроконтроллера ATMega.

Обычно сервоприводы используют питание 5В. Маломощный сервопривод можно питать от Raspberry Pi. Но если привод потребляет достаточно большой ток, или Вам нужно подключить несколько сервомашинок, лучше не нагружать Raspberry Pi и использовать отдельный источник питания. Схема подключения сервопривода:

Raspberry Pi & Servo Textronik HXT900

Управление сервоприводом с помощью программно сформированного ШИМ

Сначала попробуем формировать ШИМ для управления сервоприводом программно. Создадим скрипт 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 в код. Наличие этих функций оказывает описанную ранее проблему нестабильности программно сформированного ШИМ. Сервомашинка НЕ фиксируется в заданном положении и дергается. Если удалить инструкции print, проблема уменьшается или вообще исчезает.

Управление сервоприводом с помощью ШИМ, сформированного через 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

Теперь сервопривод работает стабильно. То есть, для управления сервоприводами о программном ШИМ желательно вообще забыть.

Подробности использования RPIO читайте здесь: http://pythonhosted.org/RPIO/pwm_py.html#examples

На этом видео видно разницу между различными способами генерирования ШИМ сигнала:

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 numberGPIO numberPin in P1 header
04P1-7
117P1-11
218P1-12
321/27 *P1-13
422P1-15
523P1-16
624P1-18
725P1-22

*RaspberryPi B и RaspberryPi B Revision 2 имеют разницу в распиновке. Подробнее здесь: http://www.avislab.com/blog/raspberry-pi-install/

Допустимые значения положения зависят от вашего сервопривода. В большинстве случаев они лежат в диапазоне от 80 до 249. Напишем следующий срипт для управления сервоприводом:

nano ./servo_blaster.py

Текст скрипта:

import time
# Servo Channel 1 => GPIO 17
servoChannel = 1
def setServo(servoChannel, position):
    servoStr ="%u=%u\n" % (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

Если Вам нужно управлять чрезвычайным количеством сервоприводов, уместно использовать многоканальный внешний ШИМ контроллер. Например Adafruit 16-channel servo driver, или его аналоги. Эта плата подключается к Raspberry Pi по интерфейсу I2C и может одновременно управлять 16-ю сервоприводами. Подробнее об этом устройстве: PWM контролер на базе микросхемы PCA9685

Успехов!

Смотри также:
Translate
Архіви

© 2011-2017 Андрій Корягін, Кременчук, Україна