Сервопривод представляет собой электропривод с обратной связью, который поддерживает заданные параметры на исполнительном органе. Конструктивно состоит из электродвигателя, редуктора и блока управления. На выходном валу редуктора установлен датчик положения, с помощью которого блок управления отслеживает положения выходного вала, обеспечивая обратную связь. Я буду рассматривать китайский сервопривод под названием Tower Pro SG90, диапазон угла поворота вала составляет 180 градусов, скорость поворота 60 градусов/0,3 секунды, применяется в основном в радиоуправляемых игрушках, роботах и т.д. Сервопривод имеет три вывода для подключения, два вывода красный (+) и коричневый (-) для питания, оранжевый вывод для управления, напряжение питания составляет 5В.
Сервоприводы я заказывал здесь. Управляется сервопривод повторяющимися импульсами определенной длительности. Ниже представлена картинка с управляющими импульсами для сервопривода SG90:
При подаче импульсов длительностью в 1,5 мс, вал сервопривода установится в среднее положение. Для импульсов шириной в 0,6 мс, вал повернется на 90 градусов по часовой стрелке относительно среднего положения (если смотреть на вал сервопривода сверху). Если ширина импульсов составит 2,5 мс, вал повернется на 90 градусов против часовой стрелки относительно среднего положения. Таким образом, положение вала задается шириной управляющего импульса. Период следования импульсов может составлять от 10 до 20 мс, за стандарт принято значение 20 мс (частота 50Гц). На самом деле данный сервопривод (SG90) может повернуться еще на несколько градусов от крайних положений, то есть диапазон угла поворота чуть больше 180 градусов. Фактически угол поворота ограничивается механическими упорами на шестеренке редуктора, вышеприведенные временные интервалы управляющих импульсов ограничивают диапазон угла поворота в пределах 180 градусов, не позволяя поворачиваться валу до механических упоров.
Ниже представлена схема подключения сервопривода к микроконтроллеру PIC16F628A:
Управление сервоприводом осуществляется двумя кнопками, при нажатии кнопки SB1 вал сервопривода плавно поворачивается по часовой стрелке, то есть происходит уменьшение ширины управляющих импульсов на линии RB4, кнопка SB2 соответственно поворачивает вал против часовой стрелки, ширина импульсов увеличивается.
Ниже представлен код программы для микроконтроллера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | #include <P16F628A.INC> LIST p=16F628A __CONFIG H'3F10' ;конфигурация микроконтроллера Sec equ 20h ;присвоение названий регистрам ОЗУ Sec1 equ 21h t1L equ 22h ;младший регистр счета длит. импульса управления t1H equ 23h ;старший регистр счета длит. импульса управления t1LL equ 24h ;промежуточный регистр t1HH equ 25h ;промежуточный регистр tmp_off equ 26h ;регистр счетчика времени flag equ 7Dh ;дополнительный регистр флагов W_TEMP equ 7Eh ;регистр для хранения значения аккумулятора W STATUS_TEMP equ 7Fh ;регистр для хранения значения STATUS ;присвоение названий линиям ввода-вывода #DEFINE serv PORTB,4 ;управляющий сигнал для сервопривода #DEFINE knp_1 PORTB,0 ;кнопка 1 #DEFINE knp_2 PORTB,1 ;кнопка 2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 0000h ;начать выполнение программы с адреса 0000h goto Start ;переход на метку Start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Подпрограмма обработки прерываний org 0004h ;начать выполнение подпрограммы с адреса 0004h movwf W_TEMP ;сохранение значений ключевых регистров swapf STATUS,W ; clrf STATUS ; movwf STATUS_TEMP ; prov_tmr1 bcf T1CON,TMR1ON ;остановка таймера TMR1 btfsc flag,0 ;проверка флага очередности goto t2 ;флаг установлен (1):перход на метку t2 t1 movf t1HH,W ;флаг очередности равен 0:перезапись длительности movwf TMR1H ;управляющего импульса из промежуточных регистров movf t1LL,W ;в регистры таймера TMR1 movwf TMR1L ; bsf flag,0 ;установка флага очередности bsf serv ;установить в 1 линию ввода/вывода serv goto extmr1 ;переход на метку extmr1 t2 bcf serv ;сбросить в 0 линию ввода/вывода serv bcf flag,0 ;сбросить флаг очередности movlw .183 ;запись длительности паузы между управляющими movwf TMR1H ;импульсами в 18,5 мс movlw .187 ; movwf TMR1L ; movlw .24 ;проверка регистра счетчика времени xorwf tmp_off,W ; btfss STATUS,Z ; goto extmr2 ;значение счетчика не равно 24:переход на extmr2 bcf PIR1,TMR1IF ;значение счетчика равно 24: сброс флага прерываний ;по переполнению TMR1 goto exxit ;переход на метку exxit extmr2 incf tmp_off,F ;инкремент регистра счетчика времени extmr1 bcf PIR1,TMR1IF ;сброс флага прерываний по переполнению TMR1 bsf T1CON,TMR1ON ;запуск таймера TMR1 exxit swapf STATUS_TEMP,W ;восстановление содержимого ключевых регистров movwf STATUS ; swapf W_TEMP,F ; swapf W_TEMP,W ; ; retfie ;выход из подпрограммы обработки прерывания ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Основная программа Start clrf PORTB ;сброс регистра PORTB clrf PORTA ;сброс регистра PORTA movlw b'00000111' ;выключение компараторов movwf CMCON bsf STATUS,RP0 ;выбрать 1-й банк movlw b'11101111' ;настройка линий ввода\вывода порта B movwf TRISB ;RB4 на выход, остальные на вход bcf STATUS,RP0 ;выбрать 0-й банк bcf flag,0 ;сброс флага очередности clrf tmp_off ;сброс счетчика времени movlw .220 ;запись длительности (1,5 мс) управляющего импульса movwf t1L ;в регистры счета и промежуточные регистры comf t1L,W ;для установки сервопривода в среднее положение movwf t1LL movlw .5 movwf t1H comf t1H,W movwf t1HH movlw b'00000000' ;коэффициент предд. TMR1 1:1, внутренний movwf T1CON ;тактовый сигнал Fosc clrf TMR1L ;сброс регистров тймера TMR1 clrf TMR1H bsf INTCON,PEIE ;разрешение прерываний периферийных модулей bcf PIR1,TMR1IF ;сброс флага прерываний по переполнению TMR1 bsf STATUS,RP0 ;выбрать 1-й банк bsf PIE1,TMR1IE ;разрешение прерываний по переполнению TMR1 bcf STATUS,RP0 ;выбрать 0-й банк bsf T1CON,TMR1ON ;запуск таймера TMR1 bsf INTCON,GIE ;глобальное разрешение прерываний opros_knp btfsc knp_1 ;опрос кнопки 1 goto met_1 ;кнопка 1 не нажата: переход на метку met_1 call povorot_1 ;кнопка 1 нажата: вызов подпрограммы povorot_1 call pausknp ;вызов подпрограммы паузы met_1 btfsc knp_2 ;опрос кнопки 2 goto opros_knp ;кнопка 2 не нажата: переход на метку opros_knp call povorot_2 ;кнопка 2 нажата: вызов подпрограммы povorot_2 call pausknp ;вызов подпрограммы паузы goto opros_knp ;переход на метку opros_knp povorot_1 movlw .2 ;проверка длительности управляющего импульса subwf t1H,W ;в регистрах счета btfss STATUS,C ; return ;длительность меньше 600 мкс, сервопривод в крайнем ;положении, выход из подпрограммы povorot_1 btfss STATUS,Z ; goto met_p11 ;длительность больше 600 мкс, переход на метку met_p11 movlw .88 ; subwf t1L,W ; btfss STATUS,C ; return ;длительность меньше 600 мкс, сервопривод в крайнем ;положении, выход из подпрограммы povorot_1 met_p11 movlw .10 ;уменьшение длительности управляющего импульса subwf t1L,F ;на 10 мкс btfsc STATUS,C ; goto met_p12 ; decf t1H,F ; met_p12 call perezap ;вызов подпрограммы perezap return ;выход из подпрограммы povorot_1 povorot_2 movf t1H,W ;проверка длительности управляющего импульса sublw .9 ;в регистрах счета btfss STATUS,C ; return ;длительность больше 2,5 мс, сервопривод в крайнем ;положении, выход из подпрограммы povorot_2 btfss STATUS,Z ; goto met_p21 ;длительность меньше 2,5 мс: переход на метку met_p21 movf t1L,W ; sublw .196 ; btfss STATUS,C ; return ;длительность больше 2,5 мс, сервопривод в крайнем ;положении, выход из подпрограммы povorot_2 met_p21 movlw .10 ;увеличение длительности управляющего импульса addwf t1L,F ;на 10 мкс btfss STATUS,C ; goto met_p22 ; incf t1H,F ; met_p22 call perezap ;вызов подпрограммы perezap return ;выход из подпрограммы povorot_1 ; perezap bsf STATUS,RP0 ;выбрать 1-й банк bcf PIE1,TMR1IE ;запрещение прерываний по переполнению TMR1 bcf STATUS,RP0 ;выбрать 0-й банк comf t1L,W ;перезапись значений регистров счета в промежуточные movwf t1LL ;регистры comf t1H,W ; movwf t1HH ; clrf tmp_off ;сброс счетчика времени bsf T1CON,TMR1ON ;включение таймера TMR1 bsf STATUS,RP0 ;выбрать 1-й банк bsf PIE1,TMR1IE ;разрешение прерываний по переполнению TMR1 bcf STATUS,RP0 ;выбрать 0-й банк return ;;выход из подпрограммы perezap pausknp movlw .14 ;подпрограмма паузы 10,5 мс movwf Sec1 ; p3 movlw .250 ; movwf Sec ; p2 decfsz Sec,F ; goto p2 ; decfsz Sec1,F ; goto p3 ; return ; ; end ; ; |
Микроконтроллер работает от внутреннего тактового генератора на частоте 4 МГц. Длительность временных интервалов для управляющих импульсов отсчитываются внутренним 16-ти разрядным таймером TMR1. При частоте в 4 МГц и коэффициенте предделителя таймера 1:1, переполнение наступит через 65536 мкс. Используя прерывание по переполнению таймера, можно отсчитывать различные временные интервалы, в диапазоне 1-65536 мкс.
Управляющие импульсы для сервопривода генерируются в подпрограмме обработки прерываний. В начале основной программы в регистры счета (t1H, t1L) записывается число 1500, соответствующее временной задержке в 1500 мкс (среднее положение вала сервопривода), следом в промежуточные регистры (t1HH, t1LL) записывается инвертированное значение числа 1500. Регистры счета используются для хранения текущей длительности импульса, промежуточные регистры выступают в роли буфера, из которых инвертированное значение длительности копируется в регистры таймера TMR1 (TMR1H, TMR1L). В регистрах счета, значение длительности представлено в удобной форме для математических операций сложения и вычитания, но перед записью в регистры таймера TMR1, значение длительности необходимо инвертировать, так как прерывание генерируются по переполнению таймера, а не по достижении конкретного значения.
Далее настраивается таймер TMR1, разрешается прерывание периферийных модулей, сбрасывается флаг переполнения, разрешается прерывание по переполнению таймера, запуск таймера, ну и разрешение глобальных прерываний.
По переполнению таймера происходит переход в обработчик прерываний, где в первую очередь выполняется остановка таймера и опрос флага очередности flag,0 (в начале основной программы флаг сбрасывается). Если флаг сброшен, происходит переход на метку t1, далее происходит перезапись длительности управляющего импульса (1500 мкс) из промежуточных регистров (t1HH, t1LL) в регистры таймера TMR1, установка флага очередности, установка в 1 линии RB4 (название линии serv). После этого сбрасывается флаг прерывания, запуск таймера и выход из обработчика прерываний. Через 1,5 мс произойдет очередной переход в обработчик прерываний по переполнению таймера, на этот раз флаг очередности равен 1, и произойдет переход на метку t2. Далее происходит сброс флага очередности и линии RB4 в 0, затем в регистры таймера записывается значение длительности паузы между импульсами, равное 18,5 мс. Дополнительно проверяется значение регистра tmp_off , который выступает в роли счетчика времени для отключения таймера TMR1, о нем будет сказано позже. Если значение регистра tmp_off не равно 24, происходит инкремент регистра, далее сброс флага прерывания, запуск таймера и выход из подпрограммы обработки прерываний.
По истечении 18,5 мс произойдет прерывание и переход в обработчик прерываний, и цикл повторится заново. Таким образом, один период управляющего сигнала (цикл) генерируется за 2 прерывания, причем длительность периода будет меняться в пределах 19,1-21 мс, в зависимости от длительности управляющего импульса.
В основной программе идет опрос кнопок SB1 и SB2, при нажатии которых происходит вызов подпрограмм povorot_1 и povorot_2 соответственно. В подпрограмме povorot_1 происходит уменьшение длительности управляющего импульса на 10 мкс (вычитание числа 10 из регистров счета t1H, t1L), в подпрограмме povorot_2 увеличение на 10 мкс (прибавление числа 10 к регистрам счета t1H, t1L). Если значение длительности меньше 0,6 мс или больше 2,5 мс выполняется выход из подпрограмм без изменения значений регистров счета, то есть происходит ограничение длительности управляющего импульса. После изменения длительности импульса происходит вызов подпрограммы perezap, в которой значения регистров счета перезаписывается в промежуточные регистры (t1HH, t1LL) в инвертированном виде. Во время перезаписи запрещается прерывание по переполнению таймера TMR1, это необходимо для получения корректного значения длительности управляющего импульса в регистрах таймера. Если не запретить прерывания, возможен случай, когда прерывание произойдет после записи старшего промежуточного регистра t1HH, а значение младшего регистра t1LL при этом останется без изменений. В таком случае в обработчике прерываний, в регистры таймера TMR1 запишется некорректное значение длительности управляющего импульса из промежуточных регистров (t1HH, t1LL). После возврата из подпрограмм perezap и povorot_1, povorot_2, вызывается подпрограмма паузы pausknp (10,5 мс), после возврата продолжается опрос кнопок.
После экспериментов с сервоприводом я заметил одну особенность, когда на вал сервопривода действует небольшой по величине постоянный внешний момент силы (нахождение под нагрузкой), происходит микро-поворот вала, сервопривод при этом пытается поддерживать заданное положение, в результате чего постоянно “жужжит”, потребляя энергию. Без нагрузки такого поведения не возникает. Чтобы избавится от этого явления, я реализовал в программе счетчик времени, если в течение определенного времени длительность управляющего импульса не меняется, то генерирование импульсов на линии RB4 прекращается. Импульсы возобновляются при нажатии кнопок SB1, SB2.
В качестве счетчика времени используется регистр tmp_off , о котором я упоминал выше, значение регистра инкрементируется в обработчике прерывания, во втором прерывании, когда выполняется запись длительности паузы между импульсами (18,5 мс) в таймер TMR1. Таким образом, счетчик инкрементируется один раз за период управляющего сигнала. Там же в обработчике прерываний происходит проверка значения счетчика, если оно равно числу 24, происходит выход из обработчика прерываний без запуска таймера TMR1, в результате генерирование управляющих импульсов прекращается. При среднем значении периода в 20 мс, генерация импульсов прекратиться через (20мс)х24=480 мс.
Генерация импульсов возобновляется при нажатии кнопок SB1, SB2, в подпрограмме perezap выполняется запуск таймера TMR1, там же происходит очистка регистра tmp_off. При длительном нажатии кнопок, подпрограмма perezap вызывается многократно и регистр tmp_off постоянно обнуляется, то есть прекращение подачи управляющих импульсов не происходит.
Величина, на которую изменяется длительность управляющего импульса при вызове подпрограмм povorot_1, povorot_2 составляет 10 мкс, всего получается (2500мкс-600мкс)/10мкс=190 дискретных значений длительности управляющего импульса. Дискретность угла поворота составит 180/190=0,94 градуса. Пауза после каждого дискретного изменения равна 10,5 мс, соответственно поворот вала сервопривода на 180 градусов займет (10,5мс)х190=1,995 секунды.
На основе этих сервоприводов я разработал поворотную платформу с радиоуправлением.
Ниже представлен видеоролик демонстрирующий работу сервопривода:
Прошивка МК и исходник + модель Proteus 7.10
Прошивка МК и исходник (автоматический возврат вала сервопривода в среднее положение)
Анатолий
16 Окт 2015Ок, пишу там где надо. У PIC16F628A есть ССР (аппаратный ШИМ) и есть внутренний генератор, который можно запустить на частоте 32 кГц. При таких условиях можно с легкостью управлять сервоприводом SG90. При этом надо лишь записать число, определяющее период (в нашем случае 20мс) в PR2 и изменяя значения в CCPR1L двигать вал привода. Вроде се просто, но я как ни бился, не могу подобрать эти значения для PR2, CCPR1L, и предделителя…
Может чем поможете….
admin
16 Окт 2015Почитайте мою статью про ШИМ и АЦП чтобы лучше разобраться с ШИМ https://radiolaba.ru/microcotrollers/ispolzovanie-moduley-atsp-i-shim-v-mikrokontrollerah-pic16.html
А так формула расчета частоты ШИМ: Fшим=Fosc/(4×(PR2+1)×(коэффициент предделителя TMR2)), отсюда выводим значение PR2=(Fosc/(4×(Fшим)×(коэффициент предделителя TMR2)))-1, для коэффициента предделителя TMR2 равному 1 и частоте тактового генератора 32кГц (частота ШИМ 50Гц) получаем PR2=(32000/(4×50×1))-1=159, при этом разрядность ШИМ составит =log(Fosc/Fшим)/log(2)=log(32000/50)/log(2)=9,32 бит, это 640 дискретных значений для периода в 20мс, длительность одного дискретного значения 31,25мкс=Tosc. Причем значение скважности придется загружать не только в регистр CCPR1L но и в два младших бита регистра CCP1CON(5:4), так как отсчет разрядов начинается именно с них.
Для сервопривода управляющий сигнал меняется в пределах 600мкс-2,5мс, для этого интервала вы получите всего (2500-600)/31,25мкс=61 дискретных положений вала сервопривода (дискретность угла поворота составит 180/61=2,9 градуса). Для получения длительности высокого уровня сигнала в 600мкс, вам надо загрузить в регистры скважности ШИМ (CCPR1L, CCP1CON(5:4)) число (600/31,25)=19, для 2500мс число (2500/31,25)=80, то есть получаем пределы чисел для скважности ШИМ 19-80, еще раз повторю загружать скважность надо с двух младших регистров CCP1CON(5:4).
Анатолий
19 Окт 2015А можно ли к RB4 подключить несколько сервоприводов?
admin
21 Окт 2015Думаю что можно, из соображений что два входа можно соединять параллельно. Но я не проверял такое на сервоприводах.
Виталий
6 Апр 2016Здравствуйте!
Можно ли сделать на одном контроллере управление двумя сервоприводами? То есть нужно управлять по 4-м портам,два из которых влево\вправо для первого серво привода, остальные два-для второго. Могли бы Вы мне помочь в этой задаче? Для первого сервопривода угол нужен 180гр.,для второго порядка 60гр.
admin
6 Апр 2016Здравствуйте. Да такое возможно.
Управление по 4-м портам это вы имеете в виду управление с помощью 4 кнопок? У меня есть подобная статья на сайте, называется – Поворотная платформа с дистанционным управлением (ссылка есть в конце статьи), там 2 сервопривода управляются 4-мя кнопками, можно регулировать скорость поворота. Возможно это то что вам нужно, только надо вырезать оттуда радиоуправление.
Александр
1 Фев 2019Здрайствуйте. Если у вас получилось сделать, не могли бы вы поделится своим опытом
Анатолий
22 Янв 2017Здравствуйте! Решил проверить один из своих сервоприводов с помощью программы из этой статьи. Так вот оказалось, что программа не рабочая. И это всего лишь из-за опечатки в строке 87. Вместо movlw b’11101111′ должно быть movlw b’11110111′. Вы могли бы исправить хотя бы в прикрепленных файлах.
admin
22 Янв 2017Здравствуйте, все правильно в программе, линия RB4 на выход, по вашему получается RB3 на выход, хотя эта линия вообще не используется. Вы видимо где-то ошибаетесь, если у вас не работает код.
Анатолий
22 Янв 2017хм, а ведь действительно получается RB3. Хотя провод подключен к 10й ноге, изменил на b’11110111′ и все заработало… ну да ладно, подскажите еще, куда в Вашем коде нужно добавить паузу (и примерно какая она должна быть), чтобы привод двигался медленнее?
admin
22 Янв 2017Надо увеличить паузу после опроса кнопок, это подпрограмма pausknp, увеличивать значение числа записываемого в регистр Sec1, строка 185 (movlw .14), в приведенном коде пауза равна 250(Sec)*3*14(Sec1)=10500 мкс, или 10,5 мс.
Gennady
13 Фев 2017Добрый вечер. А можно ли из данной схемы управления сервоприводов сделать так, чтобы при нажатии кнопки привод вращался в одну из сторон, а при отпускании сам возвращался в среднее положение. Может как то программу или схему изменить… Мне нужно для радио управлении детским катером, поворот руля как бы. Программу можно на почту ignfd@mail.ru. заранее спасибо.
admin
13 Фев 2017Здравствуйте, да это можно реализовать, программу корректировать надо, ничего не могу обещать, если время будет попробую дополнить программу.
Константин
23 Авг 2017Добрый день.
Вы случайно не занимались корректировкой программы? Тот-же самый вопрос по управлению рулём. Если возможно, очень надо. Спасибо.
admin
24 Авг 2017Здравствуйте, скорректировал прошивку, сделал автоматический возврат вала в среднее положение, файлы можно скачать в конце статьи, в архиве также есть короткое видео с демонстрацией.
Константин
24 Авг 2017Добрый день.
КЛАСС!!! Все отлично работает. Огромное спасибо за Ваш труд.
Воистину говорят, век живи – век учись. Еще раз большое спасибо.
С уважением К.
Дмитрий
4 Май 2017Доброго дня. Понравилась реализация управления. Хочу применить Вашу схему для дистанционного управления дросселем газовой колонкой с ванной комнаты, которая на кухне. Вечная беда с регулировкой газа, т.к. “прыгает” давление воды, соответственно и температуры.
К Вам просьба – скомпилировать прошивку для pic16f676 он есть в наличии, и снизить скорость вращения вала серво раз в пять.
Дмитрий
4 Май 2017Так же в наличии имеются
pic12f629
pic12f675.
Забыл еще одно, возможно еще добавиить функцию сохранения положения вала серво после откл./вкл.? Это чтоб настройка положения газового дросселя на колонке сохранялось когда закрою/открою воду.
Алексей
14 Мар 2019Здравствуйте!
Можете ли Вы сделать так, чтобы двигатель в перевернутом на 180 градусов вниз положении поворачивался на 90 градусов влево от среднего положения при нажатии кнопки SB1 и в среднее положение при нажатии кнопки SB2 за 5 секунд?
Али Николаев
18 Мар 2021Можно ли подключить серводвигатель на пик16f84a и какова будет программа?
Алексей Николаев
18 Май 2021Можно ли сделать автоматический возврат привода в крайнее положение и добавить датчик гироскоп склерометр (0)?