Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Чтение ШИМ, декодирование входного сигнала RC-приемника и применение отказоустойчивого

Компоненты и расходные материалы

Arduino UNO
× 1
Микро-серводвигатель SG90
× 2

Об этом проекте

Этот проект содержит общий, но эффективный код, который можно использовать для простого считывания RC-приемника (или любого другого сигнала ШИМ) на любом входном контакте Arduino, а также для обеспечения отказоустойчивости в случае потери сигнала передатчика.

Ниже приведено видео, показывающее, как Arduino uno действует как сервомикшер с использованием кода PWMread_RCfailsafe.ino, доступного внизу этой страницы.

К счастью, функции в PWMread_RCfailsafe.ino заботятся о регистрах прерываний за вас, и их можно легко перемещать между разными проектами, использующими разные контакты.

В примере видео ниже:

  • Устройство безопасности активируется, когда в приемнике нет сигнала от передатчика. Канал руля высоты установлен на полную мощность, а канал элеронов установлен на нейтраль.
  • Направление синего сервопривода задается положением дроссельной заслонки.
  • Диапазон движения (скорости) синего сервопривода устанавливается ползунком на боковой стороне передатчика.
  • Микширование включается или выключается переключателем передач на передатчике.

Содержание

  • Как сервоприводы управляются ШИМ
  • Примеры использования Arduino в RC-моделях / роботах
  • Обзор кода:декодирование ШИМ из RC-приемника с помощью отказоустойчивого
  • Как использовать PWMread_RCfailsafe.ino
  • Отображение частоты кадров и частоты приемника.
  • Пример сервомешивания
  • Обоснование принятого подхода.
  • Ограничения

Как сервоприводы и регуляторы скорости управляются ШИМ?

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

Вы также должны иметь практические знания:

  • IDE Arduino
  • Переменные типа Float, boolean и int.
  • Если петли
  • Для петель
  • Массивы
  • Серво-библиотека

Примеры использования Arduino в RC-моделях / роботах

Вы будете ограничены только своим воображением:

  • Применяйте сервомешалки, включайте / выключайте освещение, управляйте насосами / клапанами, устанавливайте индивидуальные последовательности ...
  • Создайте контроллер (например, стабилизацию полета / автопилот, удержание курса, удержание высоты / глубины, автоматическое выравнивание, обнаружение и уклонение, возврат домой ...)
  • Отреагирует ли ваша модель RC на потерю сигнала или низкое напряжение батареи ...
  • Используйте один и тот же передатчик для нескольких моделей / проектов без необходимости изменять какие-либо настройки или использовать функцию памяти модели.

Обзор кода:декодирование ШИМ из RC-приемника с помощью отказоустойчивого

Этот код измеряет сигналы ШИМ (широтно-импульсной модуляции), используя прерывания смены контактов. Используемые функции автоматизируют настройку прерываний и извлечение данных с любого цифрового или аналогового вывода (за исключением A6 и A7) на Arduino Uno, Nano или Pro Mini. Это делает код простым в использовании даже для новичков.

Основной целью этого проекта было создание универсального RC-приемника с отказоустойчивым «модулем», который можно быстро перемещать между проектами. Таким образом, пример кода, показанный в разделе «Как использовать», можно использовать просто как средство для достижения цели.

Примечание. этот код не будет работать с серийным программным обеспечением или любой другой библиотекой, в которой используются прерывания смены контактов.

Для тех, кому интересно, как работает код:

  • Входные контакты идентифицируются в массиве. Этот массив может быть любой длины.
  • Функция настройки разрешает прерывания при смене вывода, устанавливая соответствующие регистры для каждого вывода, указанного в массиве выводов.
  • Изменение напряжения на любом из выбранных выводов вызовет один из трех маршрутов обслуживания прерывания (ISR) в зависимости от того, к какому регистру порта принадлежит вывод ISR (PCINT0_vect) -> Порт B, ISR (PCINT1_vect) -> Порт C или ISR (PCINT2_vect) -> Порт D.
  • Внутри каждой ISR цикл FOR и операторы IF используются для определения того, какой вывод был изменен и какому каналу RC он принадлежит. Время прерывания записывается с помощью функции micros () перед возвратом к основному циклу ().
  • Временные интервалы между сменами контактов используются для расчета ширины импульса и периода повторения.
  • Флаги устанавливаются в каждой ISR, чтобы указать, когда были получены новые импульсы.
  • Затем флаги используются остальными функциями для извлечения и обработки данных, собранных ISR.

Следующее видео на YouTube Джуп Броккинг рассказывает о другом проекте, в котором используется тот же метод подключения RC-приемника к Arduino. В течение первых 8 минут Джуп четко объясняет, как используйте прерывания смены контактов для измерения сигналов ШИМ от RC-приемника.

За всеми этими деталями следит PWMread_RCfailsafe.ino, который можно скачать внизу этой страницы.

Некоторую полезную информацию о манипуляциях с портами также можно найти здесь: https://tronixstuff.com/2011/10/22/tutorial-arduino-port-manipulation/

Помимо обработки прерывания при смене вывода, была написана специальная функция RC_decode () для преобразования ширины импульса (1000–2000 мкс) в управляющий сигнал + -100% от передатчика. Отказоустойчивый проверяет действительный сигнал передатчика, используя допуски сигнала 10–330 Гц и 500–2500 мкс. Если сигнал потерян, RC_decode () возвращает заранее определенное значение отказоустойчивости.

Значения калибровки для конкретного передатчика и положения отказоустойчивости могут быть установлены для каждого канала в PWMread_RCfailsafe.ino

Как использовать PWMread_RCfailsafe.ino

Шаг 1: Пример оборудование настройка с Ардуино Уно

Если вы следуете примеру настройки с Arduino Uno, подключите приемник следующим образом:(в противном случае, если вы используете свой собственный проект, переходите сразу к шагу 2)

  • Подайте питание на приемник, используя контакты 5V и GND.
  • Подключите сигнальные контакты приемника к контактам 2–7 на Arduino с помощью перемычек «мама-папа». (Если у вас 2-канальный приемник, подключайтесь только к контактам 2 и 3)
  • В примере с сервомиксером подключите один сигнальный провод сервомашинки к контакту 9, а другой - к контакту 10.

Шаг 2. Скопируйте PWMread_RCfailsafe.ino в папку эскиза

Пример скетча RC_Read_Example был включен для загрузки внизу страницы. Вы можете использовать его в качестве основного эскиза, выполнив следующие шаги.

Скопируйте и вставьте файл PWMread_RCfailsafe.ino в папку, содержащую ваш основной эскиз. Когда вы в следующий раз откроете эскиз в IDE, появится вторая вкладка, содержащая код из PWMread_RCfailsafe.ino.

Шаг 3. Укажите the ввод булавки

Откройте или повторно откройте основной скетч в Arduino IDE.

Щелкните вкладку PWMread_RCfailsafe, прокрутите вниз до заголовка «ПЕРЕМЕННЫЕ, ОПРЕДЕЛЕННЫЕ ПОЛЬЗОВАТЕЛЕМ» и введите входные контакты в массив pwmPIN [].

Примечание. Можно использовать любое количество контактов и в любом порядке. Просто имейте в виду, что чем больше у вас будет входов, тем больше времени код потратит на обработку прерывания. Примечание. A6 и A7 являются только аналоговыми контактами и не могут использоваться.

Arduino MEGA в настоящее время не поддерживается, однако это можно было бы легко исправить, если бы было желание.

Примечание. первый элемент в pwmPIN [] - это канал 1, второй элемент - канал 2 и т. д., если вы используете все каналы от приемника, было бы неплохо убедиться, что каналы приемника 1 соответствуют каналу 1 в pwmPIN [] ...

Шаг 4: Обзор the доступно функции в PWMread_RCfailsafe.ino

Шаг 5: Печать the пульс ширина данные в серийный

Загрузите код RC_Read_Example, включите передатчик и распечатайте необработанные данные о ширине импульса в последовательный порт.

Функцию RC_avail () следует использовать для проверки, когда новые данные были получены по всем каналам, а затем использовать print_RCpwm () для отправки данных ширины импульса в последовательный порт.

Шаг 6: Откалибруйте передатчик

Использование данных ширины импульса, выводимых на последовательный порт через print_RCpwm (), для ручного изменения значений в массивах RC_min [], RC_mid [] и RC_max [] для калибровки каждого канала в диапазоне + -100%.

Шаг 7. Распечатайте откалиброванные каналы в серийный

Закомментируйте функцию print_RCpwm ()

Используйте функцию RC_decode (канал) для калибровки каждого канала в диапазоне + -1.

Затем распечатайте каждый из откалиброванных каналов как последовательный, используя функцию decimal2percentage (), за которой следует Serial.println ("")

Шаг 8: Установите отказоустойчивый

Отрегулируйте отказоустойчивые позиции в массиве RC_failsafe [] для каждого канала (в диапазоне + -1).

Включите и выключите передатчик, чтобы убедиться, что отказоустойчивый работает должным образом.

Вход RC теперь можно использовать в вашем скетче.

Примечание. Возможно, вам придется отключить любую отказоустойчивую функцию в приемнике, иначе Arduino не сможет отреагировать на потерю сигнала передатчика.

Отображение частоты кадров и частоты приемника

Период повторения импульсов приемника и частота могут быть распечатаны в последовательном формате. Перед использованием PWM_period () и PWM_freq () для извлечения данных для печати проверьте наличие новых данных на выбранном канале с помощью функции PWM_read (номер канала). Пример кода доступен в RC_FrameRate.ino.

Лучше использовать первый канал, так как это будет первый импульс, отправленный в каждом кадре приемника. PWM_read () использует те же флаги, что и RC_decode (CH), поэтому убедитесь, что сначала вызывается PWM_read ().

См. Снимок экрана ниже:

Период приемника может быть полезен, поскольку он говорит вам, сколько времени есть у кода до прибытия следующего набора данных. Если RC_avail () не обнаруживает новые данные RC по прошествии заданного времени, т.е. 21 мс, тогда запустите RC_decode (), чтобы запустить отказоустойчивый и / или продолжить выполнение программы (которая может быть ПИД-регулятором) с постоянной частотой.

Это достигается в RC_Read_Example.ino с помощью следующего оператора if.

  now =millis (); if (RC_avail () || now - rc_update> 21) rc_update =now; // обновляем входные данные RC с помощью RC_decode () // запускаем ПИД-регулятор // применяем сервомикс // позиционируем сервоприводы}  

Пример сервомикширования

Я включил RC_ServoMixer_Example.ino, чтобы показать, как можно смешивать два канала приемника (в данном случае каналы 2 и 3, руль высоты и элероны). На эскизе также показан метод установки направления сервопривода, скорости и субтриммера. Библиотека сервоприводов используется для управления сервоприводами через контакты 9 и 10.

Ниже приведен снимок экрана раздела кода сервомикширования:

Микширование достигается простым сложением и вычитанием двух каналов вместе и ограничением выходного сигнала диапазоном от -1 до +1. При применении микширования руля высоты и элеронов вы создаете два выхода, по одному для каждого сервопривода.

mix1 =канал 2 - канал3 (elv - ail)

mix2 =канал 2 + канал3 (elv - ail)

Перед установкой сервоприводов вам необходимо преобразовать сигнал + -100% (+ -1) в эквивалентную ширину импульса в микросекундах для сервопривода. В RC_ServoMixer_Example.ino я использую для этого функцию calc_uS (). Эта функция расположена внизу эскиза и показана на снимке экрана ниже.

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

Стандартный импульс нейтрали составляет 1500 мкс, а нормальный диапазон по обе стороны от нейтрали составляет + -500 мкс. Это дает минимальную ширину импульса 1000 мкс (-100%) и максимальную 2000 мкс (+ 100%). Таким образом, импульс с примененной скоростью, направлением и дополнительной подстройкой можно рассчитать следующим образом.

импульс, uS =1500 + (servo_position_% * скорости * направление + подстройка) * 500

Направление сервопривода, скорость и субтриммер могут быть статическими или динамически изменяться эскизом в ответ на входной сигнал из другого канала приемника или каким-либо другим способом.

Обоснование принятого подхода

Можно прочитать RC-приемник с помощью функции pulseIn (PIN, HIGH), однако pulseIn () блокирует код в loop (), пока он ожидает начала и затем завершения импульса, тратя драгоценное время на обработку. Если имеется более одного ввода, данные также могут быть потеряны.

Для повышения скорости лучше всего использовать функцию прерывания смены вывода Arduino вместе с прямым манипулированием портом, чтобы код в loop () работал с минимальной задержкой. Однако это более сложный и трудоемкий процесс, чем простой вызов pulseIn (PIN, HIGH).

Поэтому я хотел получить преимущества обоих миров, написав общий код, который можно перемещать между проектами. Все, что нужно, - это скопировать и вставить файл .ino (содержащий функции и процедуры прерывания) в основную папку скетча, указать входные контакты, а затем использовать функции в скетче.

Ограничения

функция micros ()

Отсчет времени в микросекундах на Arduino осуществляется с помощью функции micros (). Эта функция считает с шагом 4 мкс. Это означает, что при измерении импульсов 1000–2000 мкс у нас есть уровень точности в 4 микросекунды. С практической точки зрения этого более чем достаточно.

При желании это разрешение можно улучшить до 0,5 мкс, используя прерывания по таймеру. см. ссылку ниже:

https://www.instructables.com/id/How-to-get-an-Arduino-micros-function-with-05us-pr/

Эффективность PWMread_RCfailsafe.ino

Если вы используете PWMread_RCfailsafe.ino для чтения 6- или 9-канального приемника, 1,4–2,0% времени обработки тратится на выполнение подпрограмм прерывания смены вывода, что, я бы сказал, более чем приемлемо.

Однако всегда полезно понимать ограничения кода и то, как его можно ускорить при необходимости.

Ниже приведен список времени, необходимого для запуска каждой ISR, в зависимости от количества выбранных входных каналов.

1 канал <8uS

2 канала <12uS

3 канала <16uS

4 канала <20uS

5 каналов <20uS

6 каналов <24uS

Примечание. чем больше каналов используется, тем дольше выполняется каждая ISR. Это связано с тем, что цикл повторяется по каждому каналу каждый раз, когда вызывается ISR.

Это дополнительное время (неэффективность) незначительно при измерении низкочастотных (например, 50 Гц) RC-сигналов.

Кроме того, для входа и выхода из ISR требуется ~ 4 мкс. Для одного импульса ISR выполняется дважды:один раз в начале импульса (от низкого до высокого), а затем еще раз в конце (от высокого до низкого).

Время, необходимое для измерения 1 импульса при использовании 6 RC входов, составляет

2 * (4us для входа в ISR + 24uS для запуска ISR) =2 * 28 =48uS.

Примечание. это минимальная ширина импульса, которую можно измерить.

Время, необходимое для чтения всех 6 каналов, составляет 288 мкс (6 * 48 мкс)

Предполагая, что период повторения приемника составляет 20 миллисекунд, прерывание будет выполняться 1,44% (0,000288 / 0,02) времени. Это значительно лучше, чем использование функции pulseIn (). PulseIn () блокирует код до 20 миллисекунд для каждого вывода.

К вашему сведению: если у Arduino было только 2 входа RC, тогда ISR будет работать всего 0,16% времени (0,000032 / 0,02)

Максимальная практическая частота ( Гц)

Если вы используете этот код для каких-либо других целей, я бы предположил, что максимальная практическая частота составляет 2,5 кГц. Это дает 100 шагов разрешения функции micros () (+ - 0,025 кГц).

Если на этой частоте используется один входной вывод, 3% времени тратится на прерывание, что означает, что минимальный коэффициент заполнения, который можно измерить, составляет 0,03. Это соответствует минимальному импульсу 12 мкс.

Для более высоких частот перепишите ISR в соответствии с вашим приложением.

Код

  • PWMread_RCfailsafe
  • RC_Read_Example
  • RC_FrameRate
  • RC_ServoMixer_Example
PWMread_RCfailsafe Arduino
Этот файл .ino содержит функции и процедуры прерывания смены вывода (ISR), используемые для декодирования RC-приемника и применения отказоустойчивого режима в случае потери сигнала передатчика. Скопируйте и вставьте этот файл в ту же папку, что и основной скетч (когда вы откроете скетч, этот код появится как вторая вкладка в Arduino IDE). Затем следуйте инструкциям в файле.
 / * Kelvin Nelson 24/07/2019 * * Декодирование с широтно-импульсной модуляцией (PWM) RC-приемника с отказоустойчивым режимом * * Этот код содержит простые в использовании функции для измерения прямоугольных сигналов на любых arduiuno pro mini, nano или uno, за исключением A6 и A7. * Код предназначен для использования с RC-приемниками, но также может использоваться в большинстве других приложений измерения ШИМ как прямая замена для pulseIn (PIN, HIGH). * (на сегодняшний день он не тестировался на частоте выше 1 кГц или на Arduino Mega) * * Импульс RC-сигнала может быть преобразован из длительности импульса (1000-2000 мкс) на каждом входном контакте в - + 100 % (- + 1.0) вывод для использования в скетче. * Калибровка для этого преобразования плюс настройка отказоустойчивости могут быть установлены для каждого канала. (отказоустойчивые допуски 10–330 Гц и 500–2500 мкс). * * Необработанные данные для каждого вывода также могут быть извлечены, то есть время импульса, ширина импульса, длина кадра, коэффициент заполнения и частота. * * Настройка выполняется быстро, этот файл организован следующим образом:* * - Обзор кода * - Список функций * - Как использовать, включая примеры эскизов * - Пользовательские переменные -> указать входные контакты, передатчик калибровка и отказоустойчивость. * - Глобальные переменные и функции * * ОБЗОР КОДА:* * Код разрешает прерывания смены вывода на выбранных выводах, устанавливая соответствующие регистры. * * Изменение напряжения на любом из выбранных выводов вызовет одну из трех подпрограмм обслуживания прерывания в зависимости от того, к какому регистру принадлежит вывод. * - ISR (PCINT0_vect), ISR (PCINT1_vect) или ISR (PCINT2_vect) * * В каждой ISR код определяет, какой вывод был изменен, и записывает время перед возвратом к основному циклу (). * * Временные интервалы между сменами контактов используются для расчета ширины импульса и длины кадра. * * Флаги устанавливаются ISR, чтобы указать, когда получены новые импульсы. * * Затем флаги используются для извлечения и обработки данных, собранных каждой ISR. * * Хотя это не совсем то же самое, этот код следует принципам, аналогичным тем, которые описаны в этом видео:https://youtu.be/bENjl1KQbvo * * /// СПИСОК ФУНКЦИЙ:// ТИП ВЫВОДА НАЗВАНИЕ ФУНКЦИОНАЛЬНЫХ ЗАМЕЧАНИЙ // void setup_pwmRead () инициализирует измерение ШИМ с использованием прерываний смены контактов // ДЕКОДИРОВАНИЕ ПРИЕМНИКА RC // логическое значение RC_avail () возвращает HIGH, когда доступны новые данные RC // float RC_decode (номер канала) декодирует выбранный канал RC в диапазоне + -100 % и применяет отказоустойчивый. // void print_RCpwm () Печатает необработанные данные RC-канала в последовательный порт (используется для калибровки). // ОБЩИЕ ИЗМЕРЕНИЯ ШИМ // логическое значение PWM_read (номер канала) возвращает HIGH, когда новый импульс был обнаружен на определенном канале. // Функция сохраняет данные импульса в переменных вне подпрограмм обработки прерывания // и должна вызываться непосредственно перед использованием остальных функций ШИМ. // unsigned long PWM_time () возвращает время в начале импульса // float PWM () возвращает ширину импульса // float PWM_period () возвращает время между импульсами // float PWM_freq () вычисляет частоту // float PWM_duty () вычисляет нагрузку // ПРИМЕЧАНИЕ:PWM_read (CH) и RC_decode (CH) используют одни и те же флаги чтобы определить, когда доступны новые данные, то есть данные могут быть потеряны, если оба используются на одном канале одновременно. // ПРЕДЛОЖЕНИЕ:если вы хотите использовать PWM_read (CH), чтобы найти частоту кадров канала RC, назовите его перед RC_decode (CH). Выходные данные RC_decode (CH) по умолчанию будут работать в отказоустойчивом режиме. // КАК ИСПОЛЬЗОВАТЬ, включая примеры эскизов // под заголовком «ОПРЕДЕЛЕННЫЕ ПОЛЬЗОВАТЕЛЕМ ПЕРЕМЕННЫЕ» в приведенном ниже коде://// Шаг 1:введите входные контакты в массив pwmPIN [] ={}. //// - В pwmPIN [] можно ввести любое количество выводов (выводы доступны с 0 по 13 и A0 - A5) // - Выводы не обязательно должны быть в числовом порядке, например pwmPIN [] ={A0, 5,6,10,8} для 5 каналов или pwmPIN [] ={A0,5} для 2 каналов // - первый элемент в массиве - это номер вывода для "канала 1", а второй - вывод номер для "канала 2" ... и т. д. // - Все выводы, подключенные к RC-приемнику, должны быть в начале массива. т.е. первые 2 канала могут быть RC-входами, а третий канал может быть подключен к другому устройству, например, к выводу эхо-сигнала ультразвукового датчика. //// Шаг 2:если RC-приемник подключен ко всем входам, установите RC_inputs на 0, если не указать количество каналов, подключенных к приемнику, т.е. RC_inputs =2; //// Шаг 3:откалибруйте свой передатчик, загрузив простой эскиз с этим файлом .ino, включенным в папку эскиза, и распечатайте необработанные значения ШИМ в последовательный (альтернативно скопируйте и вставьте необходимые функции в скетч) .// Используя информацию из последовательного монитора, вручную обновите значения в массивах RC_min [], RC_mid [], RC_max [] в соответствии с вашим передатчиком (используйте полные скорости для получить лучшее разрешение). // пример скетча для печати ШИМ-данных канала RC в последовательный порт. / * void setup () {setup_pwmRead (); Serial.begin (9600); } void loop () {если (RC_avail ()) print_RCpwm (); } * /// Шаг 4:Выберите безопасную позицию для каждого канала в диапазоне от -1.0 до +1.0 и введите его в массив RC_failsafe [] ={} // Примечание:если вы хотите, чтобы Arduino реагировал на при потере сигнала передатчика вам может потребоваться отключить функцию отказоустойчивости на вашем приемнике (если она есть). // пример скетча для проверки работы отказоустойчивого и для печати откалиброванных каналов в последовательном порту:/ * unsigned long now; // временные переменные для обновления данных через равные промежутки времени unsigned long rc_update; const int каналы =6; // указываем количество каналов приемника float RC_in [channels]; // массив для хранения откалиброванного ввода от приемника void setup () {setup_pwmRead (); Serial.begin (9600); } void loop () {now =millis (); if (RC_avail () || now - rc_update> 25) {// если данные RC доступны или прошло 25 мс с момента последнего обновления (отрегулируйте в соответствии с частотой кадров приемника) rc_update =now; // print_RCpwm (); // раскомментируйте, чтобы распечатать необработанные данные из приемника в последовательный порт for (int i =0; i  =0 &&pwmPIN [i] <=7) pwmPIN_port [i] =2; // вывод принадлежит PCINT2_vect (PORT D) else if (pwmPIN [i]> =8 &&pwmPIN [i] <=13) pwmPIN_port [i] =0; // вывод принадлежит PCINT0_vect (PORT B) // преобразовываем номер вывода (т.е. вывод 11 или вывод A0) в положение вывода в регистре порта. Скорее всего, есть лучший способ сделать это, используя макрос ... // (Чтение состояния вывода непосредственно из регистров порта ускоряет код в ISR) if (pwmPIN [i] ==0 || pwmPIN [i ] ==A0 || pwmPIN [i] ==8) pwmPIN_reg [i] =0b00000001; иначе, если (pwmPIN [i] ==1 || pwmPIN [i] ==A1 || pwmPIN [i] ==9) pwmPIN_reg [i] =0b00000010; иначе, если (pwmPIN [i] ==2 || pwmPIN [i] ==A2 || pwmPIN [i] ==10) pwmPIN_reg [i] =0b00000100; иначе, если (pwmPIN [i] ==3 || pwmPIN [i] ==A3 || pwmPIN [i] ==11) pwmPIN_reg [i] =0b00001000; иначе, если (pwmPIN [i] ==4 || pwmPIN [i] ==A4 || pwmPIN [i] ==12) pwmPIN_reg [i] =0b00010000; иначе, если (pwmPIN [i] ==5 || pwmPIN [i] ==A5 || pwmPIN [i] ==13) pwmPIN_reg [i] =0b00100000; иначе, если (pwmPIN [i] ==6) pwmPIN_reg [i] =0b01000000; иначе, если (pwmPIN [i] ==7) pwmPIN_reg [i] =0b10000000; }} // НАСТРОЙКА ПРЕРЫВАНИЯ ИЗМЕНЕНИЯ ПИН-кода Избегайте setup_pwmRead () {for (int i =0; i  num_ch) RC_inputs =num_ch; // определяем количество контактов, подключенных к RC-приемнику. } // ПРЕРЫВАНИЕ СЛУЖБЫ (ISR), ИСПОЛЬЗУЕМЫЕ ДЛЯ ЧТЕНИЯ ВХОДА ШИМ // PCINT0_vect (регистр порта B) реагирует на любые изменения на выводах D8-13. // PCINT1_vect (регистр порта C) "" "" A0-A5. // PCINT2_vect (регистр порта D) "" "" D0-7. // регистры порта используются для ускорения операторов if в коде ISR:// https://www.arduino.cc/en/Reference/PortManipulation http ://tronixstuff.com/2011/10/22/tutorial-arduino-port-manipulation/// http://harperjiangnew.blogspot.co.uk/2013/05/arduino-port-manipulation-on-mega-2560 .html// READ INTERRUPTS ON PINS D8-D13:ISR routine detects which pin has changed, and returns PWM pulse width, and pulse repetition period.ISR(PCINT0_vect){ // this function will run if a pin change is detected on portB pciTime =micros(); // Record the time of the PIN change in microseconds for (int i =0; i  RC_inputs) return 0; // if channel number is out of bounds return zero. int i =CH - 1; // determine the pulse width calibration for the RC channel. The default is 1000, 1500 and 2000us. int Min; if(CH <=size_RC_min) Min =RC_min[CH-1]; else Min =1000; int Mid; if(CH <=size_RC_mid) Mid =RC_mid[CH-1]; else Mid =1500; int Max; if(CH <=size_RC_max) Max =RC_max[CH-1]; else Max =2000; float CH_output; if(FAILSAFE(CH) ==HIGH){ // If the RC channel is outside of failsafe tolerances (10-330hz and 500-2500uS) if(CH> size_RC_failsafe) CH_output =0; // and if no failsafe position has been defined, set output to neutral else CH_output =RC_failsafe[i]; // or if defined set the failsafe position } else{ // If the RC signal is valid CH_output =calibrate(PW[i],Min,Mid,Max); // calibrate the pulse width to the range -1 to 1. } return CH_output; // The signal is mapped from a pulsewidth into the range of -1 to +1, using the user defined calibrate() function in this code. // 0 represents neutral or center stick on the transmitter // 1 is full displacement of a control input is one direction (i.e full left rudder) // -1 is full displacement of the control input in the other direction (i.e. full right rudder)}/* * Receiver Calibration */ // NEED TO SPEED UPfloat calibrate(float Rx, int Min, int Mid, int Max){ float calibrated; if (Rx>=Mid) { calibrated =map(Rx, Mid, Max, 0, 1000); // map from 0% to 100% in one direction } else if (Rx ==0) { calibrated =0; // neutral } else { calibrated =map(Rx, Min, Mid, -1000, 0); // map from 0% to -100% in the other direction } return calibrated * 0.001;}// Basic Receiver FAIL SAFE// check for 500-2500us and 10-330Hz (same limits as pololu)boolean FAILSAFE(int CH){ int i =CH-1; boolean failsafe_flag =LOW; if(pwmFlag[i] ==1) // if a new pulse has been measured. { pwmFlag[i] =0; // set flag to zero if(pwmPeriod[i]> 100000) // if time between pulses indicates a pulse rate of less than 10Hz { failsafe_flag =HIGH; } else if(pwmPeriod[i] <3000) // or if time between pulses indicates a pulse rate greater than 330Hz { failsafe_flag =HIGH; } if(PW[i] <500 || PW[i]> 2500) // if pulswidth is outside of the range 500-2500ms { failsafe_flag =HIGH; } } else if (micros() - pwmTimer[i]> 100000) // if there is no new pulswidth measurement within 100ms (10hz) { failsafe_flag =HIGH; } return failsafe_flag; }/* * Quick print function of Rx channel input */void print_RCpwm(){ // display the raw RC Channel PWM Inputs for (int i =0; i =0) Serial.print(" "); if (abs(pc) <100) Serial.print(" "); if (abs(pc) <10) Serial.print(" "); Serial.print(" ");Serial.print(pc);Serial.print("% ");}/* * GENERIC PWM FUNCTIONS */unsigned long pin_time;float pin_pwm;float pin_period;boolean PWM_read(int CH){ if(CH <1 &&CH> num_ch) return false; int i =CH-1; boolean avail =pwmFlag[i]; if (avail ==HIGH){ pwmFlag[i] =LOW; noInterrupts(); pin_time =pwmTimer[i]; pin_pwm =PW[i]; pin_period =pwmPeriod[i]; прерывания (); } return avail;}unsigned long PWM_time(){return pin_time;}float PWM_period(){return pin_period;}float PWM(){return pin_pwm;}float PWM_freq(){ float freq; return freq =1000000 / pin_period; // frequency Hz}float PWM_duty(){ float duty; duty =pin_pwm/pin_period; return duty;}
RC_Read_ExampleArduino
An example sketch used to display raw data in order to calibrate your RC receiver and set your the fail safe. The PWMread_RCfailsafe.ino file should be copied into the same folder in order for the functions to be available.
unsigned long now; // timing variables to update data at a regular interval unsigned long rc_update;const int channels =6; // specify the number of receiver channelsfloat RC_in[channels]; // an array to store the calibrated input from receiver void setup() { setup_pwmRead(); Serial.begin(9600);}void loop() { now =millis(); if(RC_avail() || now - rc_update> 25){ // if RC data is available or 25ms has passed since last update (adjust to be equal or greater than the frame rate of receiver) rc_update =now; print_RCpwm(); // uncommment to print raw data from receiver to serial for (int i =0; i 
RC_FrameRateArduino
Example sketch that prints the frame rate and frequency of an RC Receiver. The PWMread_RCfailsafe.ino file should be copied into the same folder in order for the functions to be available.
void setup() { setup_pwmRead(); Serial.begin(9600);}void loop() { // Print RC receiver frame length and frame rate if (PWM_read(1)){ // if a new pulse is detected on channel 1 Serial.print(PWM_period(),0);Serial.print("uS "); Serial.print(PWM_freq());Serial.println("Hz"); }} 
RC_ServoMixer_ExampleArduino
An servo mixing example. Two channels from a 6 channel are receiver are mixed and sent to two servos controlled using the servo library. The PWMread_RCfailsafe.ino file should be copied into the same folder in order for the functions to be available.
// servo variables#include  // include the servo library to control the servosServo servo1; // name each servo output for use with the servo library Servo servo2; // Each servo must be attached to a pin that has a PWM output// on the arduino uno, nano and pro mini these pins are 3, 5, 6, 9, 10 and 11const int servo1_pin =9; // identify the pins that each servo signal wire is connected toconst int servo2_pin =10;// Select Servo Direction, Rates and Sub-trim (the size of each array must match the number of servos)boolean servo_dir[] ={0,1}; // Direction:0 is normal, 1 is reversefloat servo_rates[] ={1,0.5}; // Rates:range 0 to 2 (1 =+-500us (NORMAL), 2 =+-1000us (MAX)):The amount of servo deflection in both directionsfloat servo_subtrim[] ={0.0,0.0}; // Subtrimrange -1 to +1 (-1 =1000us, 0 =1500us, 1 =2000us):The neutral position of the servoboolean servo_mix_on =true;unsigned long now; // timing variables to update data at a regular interval unsigned long rc_update;// Receiver variablesconst int channels =6; // specify the number of receiver channelsfloat RC_in[channels]; // an array to store the calibrated input from receiver void setup() { servo1.attach(servo1_pin, 500, 2500); // attach the servo library to each servo pin, and define min and max uS values servo2.attach(servo2_pin, 500, 2500); setup_pwmRead(); Serial.begin(9600);}void loop() { now =millis(); if(RC_avail() || now - rc_update> 25){ // if RC data is available or 25ms has passed since last update (adjust to> frame rate of receiver) rc_update =now; print_RCpwm(); // uncommment to print raw data from receiver to serial for (int i =0; i 1) mix1 =1; // limit mixer output to +-1 else if(mix1 <-1) mix1 =-1; if(mix2> 1) mix2 =1; // limit mixer output to +-1 else if(mix2 <-1) mix2 =-1; // Calculate the pulse widths for the servos servo1_uS =calc_uS(mix1, 1); // apply the servo rates, direction and sub_trim for servo 1, and convert to a RC pulsewidth (microseconds, uS) servo2_uS =calc_uS(mix2, 2); // apply the servo rates, direction and sub_trim for servo 2, and convert to a RC pulsewidth (microseconds, uS) } else{ // MIXING OFF servo1_uS =calc_uS(RC_in[1],1); // apply the servo rates, direction and sub_trim for servo 1, and convert to a RC pulsewidth (microseconds, uS) servo2_uS =calc_uS(RC_in[2],2); // apply the servo rates, direction and sub_trim for servo 1, and convert to a RC pulsewidth (microseconds, uS) } servo1.writeMicroseconds(servo1_uS); // write the pulsewidth to the servo. servo2.writeMicroseconds(servo2_uS); // write the pulsewidth to the servo. }}int calc_uS(float cmd, int servo){ // cmd =commanded position +-100% // servo =servo num (to apply correct direction, rates and trim) int i =servo-1; float dir; if(servo_dir[i] ==0) dir =-1; else dir =1; // set the direction of servo travel cmd =1500 + (cmd*servo_rates[i]*dir + servo_subtrim[i])*500; // apply servo rates and sub trim, then convert to a uS value if(cmd> 2500) cmd =2500; // limit pulsewidth to the range 500 to 2500us else if(cmd <500) cmd =500; return cmd;}

Схема

This RC Receiver is powered by 5v and ground from the ICSP pins with the 6 signal outputs connected to pins 2-7
Micro servo 1 is powered by 5v pin and ground, with signal wire connected to pin 9
Micro servo 2 powered by 3.3v pin and ground, with signal wired connected to pin 10

Производственный процесс

  1. C - Вход и выход
  2. ЖК-анимация и игры
  3. Вольтметр своими руками с использованием Arduino и смартфона
  4. Регистратор данных температуры и влажности
  5. Как читать температуру и влажность на Blynk с DHT11
  6. Связь Python3 и Arduino
  7. Клеточные автоматы на основе Arduino и OLED
  8. FM-радио с использованием Arduino и RDA8057M
  9. FM-радиоприемник Arduino TEA5767
  10. Изолированный аналоговый вход для Arduino