- Принципиальная электрическая схема
- Генерация сигналов ШИМ на выводе GPIO для управления серводвигателем
- Программирование PIC16F8771A для роботизированной руки
- Моделирование кода робота-манипулятора PIC
- Дизайн печатной платы с использованием EasyEDA
- Расчет и заказ образцов онлайн
- Работа робота-манипулятора PIC
Роботы-манипуляторы можно найти повсюду, от конвейеров автомобильной промышленности до телехирургических роботов в космосе. Механизмы этих роботов похожи на человеческие, которых можно запрограммировать на аналогичную функцию и расширенные возможности. Они могут использоваться для выполнения повторяющихся действий быстрее и точнее, чем люди, или могут использоваться в суровых условиях без риска для жизни человека. Мы уже создали роботизированную руку для записи и воспроизведения, использующую Arduino, которую можно обучить выполнять конкретную задачу и заставлять ее повторять бесконечно.
В этом руководстве мы будем использовать 8-разрядный микроконтроллер PIC16F877A промышленного стандарта для управления той же роботизированной рукой с помощью потенциометров. Проблема с этим проектом заключается в том, что PIC16F877A имеет только два вывода с поддержкой PWN, но нам нужно управлять примерно 5 серводвигателями для нашего робота, для чего требуется 5 отдельных выводов PWM. Таким образом, мы должны использовать выводы GPIO и генерировать сигналы ШИМ на выводах PIC GPIO, используя прерывания таймера. Теперь, конечно, мы могли бы перейти на более совершенный микроконтроллер или использовать демультиплексорную ИС, чтобы упростить задачу. Но все же стоит попробовать этот проект для обучения.
Механическая конструкция роботизированной руки, которую я использую в этом проекте, была полностью напечатана на 3D-принтере для моего предыдущего проекта; здесь вы можете найти полные файлы дизайна и процедуру сборки. В качестве альтернативы, если у вас нет 3D-принтера, вы также можете создать простую роботизированную руку из картона, как показано по ссылке. Предполагая, что вы каким-то образом заполучили свою роботизированную руку, приступим к проекту.
Принципиальная электрическая схема
Полная принципиальная схема этого робота-манипулятора на базе микроконтроллера PIC показана ниже. Схема была нарисована с помощью EasyEDA.
Принципиальная схема довольно проста; полный проект рассчитан на питание от адаптера 12В. Затем эти 12 В преобразуются в + 5 В с помощью двух регуляторов напряжения 7805. Один обозначен как + 5V, а другой - как + 5V (2). Причина наличия двух регуляторов заключается в том, что, когда сервопривод вращается, он потребляет большой ток, который вызывает падение напряжения. Это падение напряжения вынуждает PIC перезапускаться, следовательно, мы не можем управлять PIC и серводвигателями на одной шине + 5V. Таким образом, тот, который обозначен как + 5V, используется для питания микроконтроллера PIC, ЖК-дисплея и потенциометров, а отдельный выход регулятора, обозначенный как + 5V (2), используется для питания серводвигателей.
Пять выходных контактов потенциометров, которые обеспечивают переменное напряжение от 0 В до 5 В, подключены к аналоговым контактам An0 - AN4 PIC. Поскольку мы планируем использовать таймеры для генерации ШИМ, серводвигатели могут быть подключены к любому выводу GPIO. Я выбрал контакты от RD2 до RD6 для серводвигателей, но это может быть любой GPIO по вашему выбору.
Поскольку в программе много отладки, ЖК-дисплей 16x2 также подключен к порту B PIC. Это отобразит рабочий цикл сервомоторов, которыми управляют. Помимо этого, я также расширил соединения для всех GPIO и аналоговых контактов, на всякий случай, если в будущем потребуется сопряжение каких-либо датчиков. Наконец, я также подключил вывод программатора H1, чтобы напрямую программировать PIC с помощью pickit3, используя опцию программирования ICSP.
Генерация сигналов ШИМ на выводе GPIO для управления серводвигателем
Когда схема будет готова, мы должны выяснить, как генерировать сигналы PWN на выводе GPIO PIC для управления серводвигателем. Мы уже устали от чего-то подобного с помощью метода прерывания по таймеру и добились успеха. Здесь мы просто собираемся строить поверх него, поэтому, если вы здесь новичок, я настоятельно рекомендую вам прочитать это предыдущее руководство, прежде чем продолжить.
Все серводвигатели для хобби работают с частотой 50 Гц. Это означает, что один полный импульсный цикл для серводвигателя будет 1/50 (F = 1 / T), что составляет 20 мс. Из этих полных 20 мс управляющий сигнал составляет только от 0 до 2 мс, а остальная часть сигнала всегда выключена. На рисунке ниже показано, как время включения изменяется только от 0 до 2 мс для поворота двигателя от 0 до 180 градусов из общей продолжительности 20 мс.
Имея это в виду, мы должны написать программу таким образом, чтобы PIC считывал от потенциометра от 0 до 1204 и отображал его на 0 до 100, что будет рабочим циклом серводвигателя. Используя этот рабочий цикл, мы можем рассчитать время включения серводвигателя. Затем мы можем инициализировать прерывание таймера для переполнения с регулярным интервалом, чтобы оно действовало аналогично функции millis () в Arduino. При этом мы можем переключить состояние вывода GPIO на высокий на желаемый период времени и выключить его через 20 мс (один полный цикл), а затем повторить тот же процесс. Теперь, когда мы поняли логику, давайте перейдем к программе.
Программирование PIC16F8771A для роботизированной руки
Как всегда, полную программу с видео можно найти в конце этой страницы, отсюда также можно скачать код со всеми необходимыми файлами. В этом разделе мы обсудим логику программы. Программа использует модуль АЦП, модуль таймера и модуль ЖК-дисплея для управления роботизированной рукой. Если вы не знаете, как использовать функции АЦП или функции таймера или как связать ЖК-дисплей с PIC, вы можете вернуться к соответствующим ссылкам, чтобы изучить их. Приведенное ниже объяснение дается при условии, что читатель знаком с этими концепциями.
Конфигурация порта таймера 0
Самый важный раздел кода - установка таймера 0 на переполнение для каждой конкретной задержки. Формулы для расчета этой задержки можно представить в виде
Задержка = ((256-REG_val) * (Prescal * 4)) / Fosc
Используя регистры OPTION_REG и TMR0, мы установили таймер 0 для работы с предскалярным значением 32, а значение REG val установлено на 248. Частота кварцевого резонатора (Fosc), используемая в нашем оборудовании, составляет 20 МГц. С этими значениями задержку можно рассчитать как
Задержка = ((256-248) * (32 * 4)) / (20000000) = 0,0000512 секунды (или) = 0,05 мсек.
Итак, теперь мы установили таймер на переполнение каждые 0,05 мс. Код, позволяющий сделать то же самое, приведен ниже.
/ ***** Конфигурация порта для таймера ****** / OPTION_REG = 0b00000100; // Таймер 0 с внешней частотой и 32 в качестве предскалярного // Также включает PULL UP TMR0 = 248; // Загружаем значение времени для 0,0001 с; delayValue может находиться в диапазоне 0-256 только TMR0IE = 1; // Разрешить бит прерывания таймера в регистре PIE1 GIE = 1; // Разрешить глобальное прерывание PEIE = 1; // Включение периферийного прерывания / *********** ______ *********** /
Из общего окна управления серводвигателем от 0 мс до 2 мс мы можем управлять им с разрешением 0,05 мс, что позволяет нам иметь (2 / 0,05) 40 различных положений для двигателя от 0 до 180 градусов. Вы можете дополнительно уменьшить это значение, если ваш MCU может поддерживать его для получения большего количества позиций и точного управления.
Процедура обслуживания прерывания (ISR)
Теперь, когда таймер 0 настроен на переполнение каждые 0,05 мс, у нас будет установлен флаг прерывания TMR0IF на 0,05 мс. Итак, внутри функции ISR мы можем сбросить этот флаг и увеличить переменную count на единицу. Теперь эта переменная будет увеличиваться на 1 каждые 0,05 мс.
void interrupt timer_isr () { if (TMR0IF == 1) // Флаг таймера сработал из-за переполнения таймера -> устанавливается на переполнение каждые 0,05 мс { TMR0 = 248; // Загрузить значение таймера TMR0IF = 0; // Сброс флага прерывания таймера count ++; // Считаем приращения на 1 каждые 0,05 мс }
Расчет рабочего цикла и времени
Затем мы должны рассчитать рабочий цикл и время для всех пяти серводвигателей. У нас есть пять серводвигателей, каждый из которых используется для управления отдельной секцией руки. Таким образом, мы должны прочитать значение АЦП всех пяти и вычислить рабочий цикл и время для каждого.
Значение АЦП будет в диапазоне от 0 до 1024, которое можно преобразовать в рабочий цикл от 0% до 100%, просто умножив 0,0976 (100/1024 = 0,0976) на полученное значение. Затем этот рабочий цикл от 0 до 100% необходимо преобразовать во время включения. Мы знаем, что при 100% рабочем цикле время включения должно составлять 2 мс (для 180 градусов), поэтому умножение 0,02 (2/100 = 0,02) преобразует рабочий цикл от 0 до 100 в 0 до 2 мс. Но тогда количество переменных таймера будет увеличиваться один раз на каждые 0,05 мс. Это означает, что значение счета будет 20 (1 / 0,05 = 20) на каждые 1 мс. Итак, мы должны умножить 20 на 0,02, чтобы вычислить точное время для нашей программы, которое даст нам значение 0,4 (0,02 * 20 = 0,4). Код для этого же показан ниже, вы можете увидеть, как он повторяется 5 раз для всех 5 горшков, используя цикл for. Полученные значения сохраняются в массиве T_ON.
для (int pot_num = 0; pot_num <= 3; pot_num ++) { int Pev_val = T_ON; POT_val = (ADC_Read (pot_num)); // Считываем значение POT с помощью ADC Duty_cycle = (POT_val * 0.0976); // Сопоставить от 0 до 1024 с 0 до 100 T_ON = Duty_cycle * 0.4; // 20 * 0.02
Выбор двигателя для вращения
Мы не можем управлять всеми пятью двигателями вместе, так как это сильно затруднит выполнение кода ISR, замедляющего работу всего микроконтроллера. Таким образом, мы должны вращать только один серводвигатель за раз. Чтобы выбрать сервопривод для вращения, микроконтроллер отслеживает время включения всех пяти серводвигателей и сравнивает его с предыдущим временем. Если есть изменение во времени включения, то мы можем сделать вывод, что необходимо переместить конкретный сервопривод. Код для того же показан ниже.
если (T_ON! = Pev_val) { Lcd_Clear (); серво = pot_num; Lcd_Set_Cursor (2,11); Lcd_Print_String ("S:"); Lcd_Print_Char (серво + '0'); если (pot_num == 0) {Lcd_Set_Cursor (1,1); Lcd_Print_String ("A:");} иначе, если (pot_num == 1) {Lcd_Set_Cursor (1,6); Lcd_Print_String ("B:");} иначе, если (pot_num == 2) {Lcd_Set_Cursor (1,11); Lcd_Print_String ("C:");} иначе, если (pot_num == 3) {Lcd_Set_Cursor (2,1); Lcd_Print_String ("D:");} иначе, если (pot_num == 4) {Lcd_Set_Cursor (2,6); Lcd_Print_String ("E:");} char d2 = (Duty_cycle)% 10; char d1 = (Duty_cycle / 10)% 10; Lcd_Print_Char (d1 + '0'); Lcd_Print_Char (d2 + '0');
Мы также печатаем рабочий цикл сервопривода на ЖК-экране, чтобы пользователь мог знать его текущее положение. В зависимости от изменения времени включения переменный сервопривод обновляется числами от 0 до 4, каждое из которых представляет отдельные двигатели.
Управление серводвигателем внутри ISR
Внутри ISR у нас есть счетчик переменных, увеличивающийся каждые 0,05 мс, это означает, что на каждые 1 мс значение переменной будет увеличиваться на 20. Используя это, мы должны управлять выводами для получения сигнала ШИМ. Если значение счетчика меньше, чем время включения, то GPIO этого двигателя включается, используя следующую строку
PORTD = PORTD - servo_code;
Здесь массив servo_code содержит данные о выводах всех пяти серводвигателей, и на основе значения переменной servo будет использоваться код для этого конкретного серводвигателя. Затем выполняется логическое ИЛИ (-) с существующими битами PORTD, чтобы мы не влияли на значения другого двигателя и обновляли только этот конкретный двигатель. Аналогично выключению булавки
PORTD = PORTD & ~ (servo_code);
Мы изменили значение бита на противоположное, используя оператор логического обратного (~), а затем выполнили операцию И (&) над PORTD, чтобы выключить только нужный вывод, оставив остальные выводы в их предыдущем состоянии. Полный фрагмент кода показан ниже.
void interrupt timer_isr () { if (TMR0IF == 1) // Флаг таймера сработал из-за переполнения таймера -> устанавливается на переполнение каждые 0,05 мс { TMR0 = 248; // Загрузить значение таймера TMR0IF = 0; // Сброс флага прерывания таймера count ++; // Подсчет с шагом 1 на каждые 0,05 мс -> счет будет 20 на каждые 1 мс (0,05 / 1 = 20)) } int servo_code = {0b01000000, 0b00100000, 0b00010000, 0b00001000, 0b00000100}; если (count> = 20 * 20) count = 0; if (count <= (T_ON)) PORTD = PORTD - servo_code; иначе PORTD = PORTD & ~ (servo_code); }
Мы знаем, что полный цикл должен длиться 20 мс, прежде чем снова будет включен вывод GPIO. Поэтому мы проверяем, превысил ли счетчик 20 мс, сравнивая значение счетчика с 400 (тот же расчет, что обсуждался выше), и если да, мы должны снова инициализировать счетчик, чтобы он был равен нулю.
Моделирование кода робота-манипулятора PIC
Всегда лучше смоделировать код, прежде чем переносить его на реальное оборудование. Поэтому я использовал Proteus для моделирования своего кода и проверил, что он работает правильно. Схема, используемая для моделирования, показана ниже. Мы использовали осциллограф, чтобы проверить, генерируются ли сигналы ШИМ должным образом. Также мы можем проверить, вращаются ли ЖК-дисплей и сервомоторы должным образом.
Как вы можете видеть, на ЖК-дисплее отображается рабочий цикл двигателя D, равный 07 на основе значения потенциометра, которое является 3- м двигателем. Аналогично, если другой горшок перемещается, рабочий цикл этого горшка и номер его двигателя будут отображаться на ЖК-дисплее. Сигнал ШИМ, отображаемый на осциллографе, показан ниже.
Общий период цикла составляет 22,2 мс с использованием опции курсора на осциллографе, что очень близко к желаемым 20 мс. Наконец, мы уверены, что код работает, поэтому для продолжения работы со схемой мы можем либо припаять его на перфорированной плате, либо использовать печатную плату. Это будет нелегко работать на макетной плате, потому что POT всегда имеет тенденцию давать некоторые проблемы из-за плохого соединения.
Дизайн печатной платы с использованием EasyEDA
Чтобы разработать этот роботизированный манипулятор PIC, мы выбрали онлайн-инструмент EDA под названием EasyEDA. Я использую его в течение долгого времени и считаю его очень удобным из-за большой доступности и простоты использования. После проектирования печатной платы мы можем заказать образцы печатной платы в их недорогих услугах по изготовлению печатных плат. Они также предлагают услуги по подбору компонентов, если у них есть большой запас электронных компонентов, и пользователи могут заказать необходимые компоненты вместе с заказом печатной платы.
При разработке схем и печатных плат вы также можете сделать общедоступными свои схемы и конструкции печатных плат, чтобы другие пользователи могли их копировать или редактировать и извлекать выгоду из вашей работы. Мы также сделали общедоступными макеты всех схем и печатных плат для этой схемы, проверьте ссылка ниже:
easyeda.com/circuitdigest/pic-development-board-for-robotic-arm
По этой ссылке вы можете напрямую заказать ту же печатную плату, которую мы используем в этом проекте, и использовать ее. После завершения проектирования плату можно рассматривать как трехмерную модель, которая будет очень полезна для визуализации того, как плата будет выглядеть после изготовления. Трехмерная модель платы, которую мы используем, показана ниже. Помимо этого, вы также можете просмотреть верхний и нижний слой платы, чтобы проверить, соответствует ли гладкий экран ожидаемому.
Расчет и заказ образцов онлайн
После завершения проектирования этой печатной платы робота PIC вы можете заказать печатную плату на сайте JLCPCB.com. Чтобы заказать печатную плату в JLCPCB, вам потребуется файл Gerber. Чтобы загрузить файлы Gerber для вашей печатной платы, просто нажмите кнопку Generate Fabrication File на странице редактора EasyEDA, затем загрузите файл Gerber оттуда или вы можете щелкнуть Order at JLCPCB, как показано на изображении ниже. Это перенаправит вас на JLCPCB.com, где вы можете выбрать количество плат, которые вы хотите заказать, сколько слоев меди вам нужно, толщину печатной платы, вес меди и даже цвет печатной платы, как на снимке, показанном ниже:
После того, как вы выбрали все параметры, нажмите «Сохранить в корзину», после чего вы попадете на страницу, где вы можете загрузить свой файл Gerber, который мы загрузили с EasyEDA. Загрузите свой файл Gerber и нажмите «Сохранить в корзину». И, наконец, нажмите «Оформить заказ», чтобы завершить заказ, и через несколько дней вы получите свои печатные платы. Они производят печатную плату по очень низкой цене - 2 доллара. Их время сборки также очень мало, что составляет 48 часов с доставкой DHL 3-5 дней, в основном вы получите свои печатные платы в течение недели с момента заказа.
После заказа печатной платы вы можете проверить ход производства вашей печатной платы с указанием даты и времени. Вы проверяете это, перейдя на страницу «Аккаунт» и щелкнув «Прогресс производства».
После нескольких дней заказа печатных плат я получил образцы печатных плат в красивой упаковке, как показано на рисунках ниже.
И после получения этих деталей я припаял все необходимые компоненты на печатную плату. Я также напрямую припаял POT напрямую, вместо того, чтобы использовать соединительные провода, потому что провода между гнездом и гнездом, которые я изначально использовал, давали странные аналоговые выходные напряжения, вероятно, из-за слабых контактов. Когда все компоненты были собраны, моя печатная плата выглядела примерно так.
Вы могли заметить, что на этой плате всего один 7805. Это потому, что сначала я думал, что могу обойтись одним регулятором для питания PIC и серводвигателя, а позже я понял, что мне нужно два. Итак, я использовал внешнюю цепь для питания серводвигателей через зеленые провода, которые вы видите здесь.
Тем не менее, вам не нужно сильно об этом беспокоиться, потому что; Я внес изменения в печатную плату. Вы можете использовать модифицированную печатную плату и припаять оба регулятора на самой плате.
Работа робота-манипулятора PIC
После всей утомительной работы пора расплачиваться. Спаяйте все компоненты на плате и загрузите программу в контроллер PIC. Полный код приведен ниже или может быть загружен отсюда. Разъем для программирования, предусмотренный на плате, должен помочь вам загрузить программу напрямую с помощью Pickit 3 без особых хлопот. После загрузки программы вы должны увидеть на ЖК-дисплее сервопривод, которым в данный момент управляют. Чтобы узнать больше о программировании микроконтроллера PIC, просто следуйте предыдущему руководству.
Оттуда вы можете просто повернуть горшок и проверить, как серводвигатели реагируют на каждый потенциометр. Как только вы поймете формат, вы можете управлять роботизированной рукой, чтобы выполнять любое действие, которое вам нужно, и получать удовольствие. Вы можете найти полную работу над проектом в видео по ссылке ниже.
Вот и все, ребята, надеюсь, вы поняли проект и узнали из него что-то новое. Если у вас есть какие-либо вопросы, оставьте их в разделе комментариев или используйте форумы для других технических обсуждений.