Сервопривод — это мотор-редуктор, способный поворачивать выходной вал в заданное положение (на заданный угол) и удерживать его в этом положении, вопреки сопротивлениям и возмущениям. Сервопривод Tower Pro 9g SG90 не имеет мощные характеристики (всего 1,2-1,6 кг*см), но имеет недорогую цену. Отлично подходит для управления небольшими легкими механизмами под управлением контроллеров Arduino, Raspberry Pi и т.п.. Рабочее напряжение Tower Pro 9g SG90 от 3В до 7.2В, угол поворота ограничен диапазоном от 0 до 180 градусов (в реальность — чуть больше).
В этой статье будем управлять сервоприводом SG90 с помощью PCA9685 из Python на Orange Pi PC. Можно использовать Raspberry Pi, Banana Pi, NanoPi или любой другой мини-компьютер под управлением ОС Linux имеющий I2C порт.
Библиотека на Python для PCA9685
Поскольку библиотека Adafruit_Python_PCA9685 для работы с PCA9685 из Python работает только на Raspberry Pi, она была переписана так, чтобы ее можно было использовать на Orange Pi и Banana Pi. Теперь используется SMBus в качестве I2C драйвера, как установить тут: SMBus: Работа с шиной I2C на Python в Raspberry Pi/Orange Pi/Banana Pi.
Файл PCA9685.py
import logging import time import math # Based on Adafruit Lib: # https://github.com/adafruit/Adafruit_Python_PCA9685/blob/master/Adafruit_PCA9685/PCA9685.py # Default address: PCA9685_ADDRESS = 0x40 # Registers/etc: MODE1 = 0x00 MODE2 = 0x01 SUBADR1 = 0x02 SUBADR2 = 0x03 SUBADR3 = 0x04 PRESCALE = 0xFE LED0_ON_L = 0x06 LED0_ON_H = 0x07 LED0_OFF_L = 0x08 LED0_OFF_H = 0x09 ALL_LED_ON_L = 0xFA ALL_LED_ON_H = 0xFB ALL_LED_OFF_L = 0xFC ALL_LED_OFF_H = 0xFD # Bits: RESTART = 0x80 SLEEP = 0x10 ALLCALL = 0x01 INVRT = 0x10 OUTDRV = 0x04 # Channels CHANNEL00 = 0x00 CHANNEL01 = 0x01 CHANNEL02 = 0x02 CHANNEL03 = 0x03 CHANNEL04 = 0x04 CHANNEL05 = 0x05 CHANNEL06 = 0x06 CHANNEL07 = 0x07 CHANNEL08 = 0x08 CHANNEL09 = 0x09 CHANNEL10 = 0x0A CHANNEL11 = 0x0B CHANNEL12 = 0x0C CHANNEL13 = 0x0D CHANNEL14 = 0x0E CHANNEL15 = 0x0F class PCA9685(object): def __init__(self, i2cBus, address=PCA9685_ADDRESS): self.i2cBus = i2cBus self.address = address self.begin() def begin(self): """Initialize device""" self.set_all_pwm(0, 0) self.i2cBus.write_byte_data(self.address, MODE2, OUTDRV) self.i2cBus.write_byte_data(self.address, MODE1, ALLCALL) time.sleep(0.005) # wait for oscillator mode1 = self.i2cBus.read_byte_data(self.address, MODE1) mode1 = mode1 & ~SLEEP # wake up (reset sleep) self.i2cBus.write_byte_data(self.address, MODE1, mode1) time.sleep(0.005) # wait for oscillator def reset(self): self.i2cBus.write_byte_data(self.address, MODE1, RESTART) time.sleep(0.01) def set_address(self, address): """Sets device address.""" self.address = address def set_i2c_bus(self, i2cBus): """Sets I2C Bus.""" self.i2cBus = i2cBus def set_pwm(self, channel, on, off): """Sets a single PWM channel.""" self.i2cBus.write_byte_data(self.address, LED0_ON_L + 4 * channel, on & 0xFF) self.i2cBus.write_byte_data(self.address, LED0_ON_H + 4 * channel, on >> 8) self.i2cBus.write_byte_data(self.address, LED0_OFF_L + 4 * channel, off & 0xFF) self.i2cBus.write_byte_data(self.address, LED0_OFF_H + 4 * channel, off >> 8) def set_all_pwm(self, on, off): """Sets all PWM channels.""" self.i2cBus.write_byte_data(self.address, ALL_LED_ON_L, on & 0xFF) self.i2cBus.write_byte_data(self.address, ALL_LED_ON_H, on >> 8) self.i2cBus.write_byte_data(self.address, ALL_LED_OFF_L, off & 0xFF) self.i2cBus.write_byte_data(self.address, ALL_LED_OFF_H, off >> 8) def set_pwm_freq(self, freq_hz): """Set the PWM frequency to the provided value in hertz.""" prescaleval = 25000000.0 # 25MHz prescaleval /= 4096.0 # 12-bit prescaleval /= float(freq_hz) prescaleval -= 1.0 prescale = int(math.floor(prescaleval + 0.5)) oldmode = self.i2cBus.read_byte_data(self.address, MODE1) newmode = (oldmode & 0x7F) | 0x10 # sleep self.i2cBus.write_byte_data(self.address, MODE1, newmode) # go to sleep self.i2cBus.write_byte_data(self.address, PRESCALE, prescale) self.i2cBus.write_byte_data(self.address, MODE1, oldmode) time.sleep(0.005) self.i2cBus.write_byte_data(self.address, MODE1, oldmode | 0x80) def __enter__(self): return self def __exit__(self, exception_type, exception_value, traceback): self.reset()
Описание методов (функций)
__init__()
Конструктор класса.
__init__(self, i2cBus, address=PCA9685_ADDRESS)
Параметры
i2cBus
— Объект типа PCA9685.
address
— I2C адрес устройства. По умолчанию PCA9685_ADDRESS = 0x40
.
begin()
Инициализация устройства.
begin(self)
set_address()
Установка адреса устройства.
set_address(self, address)
Параметры
address
— I2C адрес устройства.
set_i2c_bus()
Установка I2C шины.
set_i2c_bus(self, i2cBus)
Параметры
i2cBus
— Объект типа PCA9685.
set_pwm()
Устанавливает ШИМ одного из выводов PCA9685.
set_pwm(self, channel, on, off)
Параметры
channel
— Один из выводов PWM от 0 до 15.
on
— В какой момент цикла из 4096 частей включить ШИМ.
off
— В какой момент цикла из 4096 частей выключить ШИМ.
set_all_pwm()
Устанавливает ШИМ на все выводы PCA9685.
set_all_pwm(self, on, off)
Параметры
on
— В какой момент цикла из 4096 частей включить ШИМ.
off
— В какой момент цикла из 4096 частей выключить ШИМ.
set_pwm_freq()
Устанавливает частоту ШИМ для всего чипа, до ~ 1,6 кГц.
set_pwm_freq(self, freq_hz)
Параметры
freq_hz
— Частота в Герцах.
Библиотека на Python для сервоприводов
Для более удобного управления сервоприводом, основные функции были собраны в одном классе — ServoPCA9685
. Тут можно найти минимальную (servo_min = 130
) и максимальную (servo_max = 510
) длину импульса для безопасного управления сервоприводом SG90.
# Configure min and max servo pulse lengths servo_min = 130 servo_max = 510
Если ваш сервопривод работает с другими значениями, тогда вы можете редактировать их.
Файл ServoPCA9685.py
import time # Servo with PCA9685 implementation # Configure min and max servo pulse lengths servo_min = 130 # Min pulse length out of 4096 / 150/112 servo_max = 510 # Max pulse length out of 4096 / 600/492 def map(x, in_min, in_max, out_min, out_max): return (x - in_min) * (out_max - out_min + 1) / (in_max - in_min + 1) + out_min class ServoPCA9685(object): def __init__(self, pca9685, channel): self.pca9685 = pca9685 self.channel = channel self.set_pwm_freq(50) self.set_pulse(300) def set_pwm_freq(self, freq=50): self.pca9685.set_pwm_freq(freq) time.sleep(0.005) def set_angle(self, angle): self.set_pulse(map(angle, 0, 180, servo_min, servo_max)) def set_pulse(self, pulse): if pulse >= servo_min and pulse <= servo_max: self.pca9685.set_pwm(self.channel, 0, pulse) time.sleep(0.005) def disable(self): self.pca9685.set_pwm(self.channel, 0, 0) time.sleep(0.005)
Описание методов (функций)
__init__()
Конструктор класса.
__init__(self, pca9685, channel)
pca9685
— Объект типа PCA9685.
channel
— Один из ШИМ выводов PCA9685 от 0 до 15.
set_pwm_freq()
Установка частоты ШИМ для вашего сервопривода.
set_pwm_freq(self, freq=50)
freq
— Частота в Герцах. По умолчанию freq=50
.
set_angle()
Установка примерного угла сервопривода.
set_angle(self, angle)
angle
— Угол от 0 до 180 градусов.
set_pulse()
Установка длины импульса.
set_pulse(self, pulse)
pulse
— Длина ШИМ импульса.
disable()
Отключение сервопривода (установка длины импульса в ноль «0»).
disable(self)
Примеры программ
Схема подключения сервопривода SG90 к PCA9685
Управление одним сервоприводом SG90
Чтобы управлять сервоприводом посредством PCA9685 нужно соблюдать следующие шаги:
- Нужно открыть шину I2C «0» (или «1»);
i2cBus = smbus.SMBus(0)
- Создаём объект класса
PCA9685
, а в качестве параметра конструктора используем выше созданный объект:i2cBus
;pca9685 = PCA9685.PCA9685(i2cBus)
- Создаём объект класса
ServoPCA9685
для управления одного сервопривода, в качестве первого параметра используем выше созданный объект,pca9685
, а второй параметр — это номер канала PCA9685, можно выбрать следующие значения:PCA9685.CHANNEL00
,PCA9685.CHANNEL01
,PCA9685.CHANNEL02
, …,PCA9685.CHANNEL15
или номера от 0 до 15;servo00 = ServoPCA9685.ServoPCA9685(pca9685, PCA9685.CHANNEL00)
- Для управления сервоприводом можно использовать два метода, а именно:
set_pulse(pulse)
, гдеpulse
— это длина ШИМ импульса отservo_min = 130
доservo_max = 510
; иset_angle(angle)
, гдеangle
— это угол поворота от 0 до 180 градусов, метод (функция) пропорционально переносит значение из текущего диапазона значений в градусах (от 0 до 180) в новый диапазон (от 130 до 510) в импульсах.
Нижеприведённый пример кода поварачивает сервопривод в одну сторону,
# 130 -> 510 for pulse in range(ServoPCA9685.servo_min, ServoPCA9685.servo_max + 1): servo00.set_pulse(pulse) time.sleep(0.01)
потом в другую
# 510 -> 130 for pulse in reversed(range(ServoPCA9685.servo_min, ServoPCA9685.servo_max + 1)): servo00.set_pulse(pulse) time.sleep(0.01)
с использованием метода set_pulse(pulse)
, а в конце отключает подаваемый на сервопривод ШИМ.
servo00.disable()
Файл servo_1x_pulse.py
Пример управления сервоприводом используя метод set_pulse(pulse)
.
import time import smbus import PCA9685 import ServoPCA9685 i2cBus = smbus.SMBus(0) pca9685 = PCA9685.PCA9685(i2cBus) servo00 = ServoPCA9685.ServoPCA9685(pca9685, PCA9685.CHANNEL00) # 130 -> 510 for pulse in range(ServoPCA9685.servo_min, ServoPCA9685.servo_max + 1): servo00.set_pulse(pulse) time.sleep(0.01) # 510 -> 130 for pulse in reversed(range(ServoPCA9685.servo_min, ServoPCA9685.servo_max + 1)): servo00.set_pulse(pulse) time.sleep(0.01) servo00.disable()
Файл servo_1x_angle.py
Пример управления сервоприводом используя метод set_angle(angle)
.
import time import smbus import PCA9685 import ServoPCA9685 i2cBus = smbus.SMBus(0) pca9685 = PCA9685.PCA9685(i2cBus) servo00 = ServoPCA9685.ServoPCA9685(pca9685, PCA9685.CHANNEL00) # 0 - > 180 for angle in range(0, 180 + 1): servo00.set_angle(angle) time.sleep(0.01) # 180 -> 0 for angle in reversed(range(0, 180 + 1)): servo00.set_angle(angle) time.sleep(0.01) servo00.disable()
Управление несколькими сервоприводами SG90
Управлять несколькими сервоприводами можно аналогичным способом, как и одним. Единственное отличие в том, что нужно создать для каждого сервопривода отдельный экземпляр класса ServoPCA9685
. К примеру:
servo00 = ServoPCA9685.ServoPCA9685(pca9685, PCA9685.CHANNEL00) servo01 = ServoPCA9685.ServoPCA9685(pca9685, PCA9685.CHANNEL01) servo02 = ServoPCA9685.ServoPCA9685(pca9685, PCA9685.CHANNEL02) servo03 = ServoPCA9685.ServoPCA9685(pca9685, PCA9685.CHANNEL03)
каждый объект должен иметь отличное от других имя и свой собственный канал (от 0 до 15).
servo_Nx_pulse.py
Пример управления несколькими (четырьмя) сервоприводами используя метод set_pulse(pulse)
.
import time import smbus import PCA9685 import ServoPCA9685 i2cBus = smbus.SMBus(0) pca9685 = PCA9685.PCA9685(i2cBus) servo00 = ServoPCA9685.ServoPCA9685(pca9685, PCA9685.CHANNEL00) servo01 = ServoPCA9685.ServoPCA9685(pca9685, PCA9685.CHANNEL01) servo02 = ServoPCA9685.ServoPCA9685(pca9685, PCA9685.CHANNEL02) servo03 = ServoPCA9685.ServoPCA9685(pca9685, PCA9685.CHANNEL03) # 130 -> 510 for pulse in range(ServoPCA9685.servo_min, ServoPCA9685.servo_max + 1): servo00.set_pulse(pulse) servo01.set_pulse(pulse) servo02.set_pulse(pulse) servo03.set_pulse(pulse) time.sleep(0.01) # 510 -> 130 for pulse in reversed(range(ServoPCA9685.servo_min, ServoPCA9685.servo_max + 1)): servo00.set_pulse(pulse) servo01.set_pulse(pulse) servo02.set_pulse(pulse) servo03.set_pulse(pulse) time.sleep(0.01) servo00.disable() servo01.disable() servo02.disable() servo03.disable()
Материалы
Все файлы в одном архиве (Скачать zip архив)
SMBus: Работа с шиной I2C на Python в Raspberry Pi/Orange Pi/Banana Pi
GitHub — adafruit/Adafruit_Python_PCA9685: Python code to use the PCA9685 PWM servo/LED controller with a Raspberry Pi or BeagleBone black.
Теперь роборуку можно собрать не только на Малинке, но и на апельсинке.
Совершенно верно, уже не составит труда управлять роборукой
Hello there! I know this is kinda off topic but I was wondering if you knew where I could find a captcha plugin for my comment form?
I’m using the same blog platform as yours and I’m having
problems finding one? Thanks a lot!
%%
This sequel doubtless starts with Billy feeling unsure about if he is a adequate superhero.
Excellent web site you’ve got here.. It’s difficult to find quality writing like yours nowadays.
I honestly appreciate people like you! Take care!!
Have you ever thought about adding a little bit more than just your articles?
I mean, what you say is important and everything. Nevertheless think
of if you added some great photos or video clips to give your posts more, «pop»!
Your content is excellent but with images and video clips, this
website could definitely be one of the very best in its field.
Very good blog!
This paragraph provides clear idea designed for
the new viewers of blogging, that genuinely how to do blogging and site-building.
Great website. A lot of helpful info here. I am sending it to several friends ans also sharing in delicious.
And of course, thanks to your sweat!
My brother recommended I would possibly like this web site.
He was once entirely right. This put up truly made my day.
You cann’t consider just how much time I had spent for this information!
Thank you!
Hey There. I found your blog using msn. This is an extremely well
written article. I’ll be sure to bookmark it and return to read more of your useful information. Thanks for the post.
I will certainly comeback.
Receive promo code by e mail following ticket buy.
Tremendous things here. I am very happy to look your post.
Thanks a lot and I’m looking forward to contact you.
Will you kindly drop me a e-mail?
Hello there I am so thrilled I found your webpage, I really found you by accident,
while I was browsing on Aol for something else, Anyways I
am here now and would just like to say thanks for a marvelous post
and a all round entertaining blog (I also love the theme/design), I don’t have time to go
through it all at the moment but I have book-marked it and also added in your RSS feeds, so when I have time I will be back
to read more, Please do keep up the awesome job.
Review my web site — whatsapp mod
%%
My spouse and I stumbled over here different page and thought I may
as well check things out. I like what I see so
now i am following you. Look forward to checking out your web
page repeatedly.
Here is my page … GB WhatsApp
What’s up to all, how is the whole thing, I think every one is getting more from this web
page, and your views are nice in support of new users.
%%
I always spent my half an hour to read this web site’s articles or
reviews everyday along with a cup of coffee.