Leitor PWM Eficiente para Arduino & Decodificador de Receptor RC com Fail-Safe Integrado
Componentes e Materiais
| Arduino UNO | 1 |
| Micro servo SG90 | 2 |
Sobre o Projeto
Este projeto traz código genérico e eficiente para ler receptor RC (ou qualquer sinal PWM) em qualquer pino de entrada do Arduino, com fail-safe para perda de sinal do transmissor.
Vídeo demonstra Arduino Uno como mixer de servos usando PWMread_RCfailsafe.ino (disponível no final). As funções gerenciam registradores de interrupção automaticamente, facilitando mover entre projetos com pinos diferentes.
No Exemplo do Vídeo:
- Fail-safe ativa sem sinal do transmissor: canal elevator = full up, aileron = neutro
- Direção do servo azul = posição do throttle
- Amplitude (rates) do servo azul = slider lateral do transmissor
- Mixer liga/desliga = switch gear do transmissor
Sumário
- Como servos são controlados por PWM
- Exemplos de uso de Arduino em modelos RC/robôs
- Visão geral do código: decodificar PWM de receptor RC com fail-safe
- Como usar
PWMread_RCfailsafe.ino - Exibir taxa de quadros e frequência do receptor
- Exemplo de mixer de servos
- Racional da abordagem
- Limitações
Como Servos e Controladores de Velocidade São Controlados por PWM?
Assume-se entendimento de sinais PWM para servos/ESCs. Bom vídeo explicativo aqui.
Conhecimentos necessários:
- Arduino IDE
- Variáveis float, boolean, int
- Loops if/for
- Arrays
- Biblioteca Servo
Exemplos de Uso de Arduino em Modelos RC/Robôs
Limite é sua imaginação:
- Mixer de servos, ligar/desligar luzes, controlar bombas/válvulas, sequências personalizadas…
- Criar controlador (estabilização de voo/autopiloto, hold de heading/altitude/profundidade, auto-level, sense-and-avoid, return-to-home…)
- Responder a perda de sinal ou baixa tensão de bateria…
- Usar mesmo transmissor para múltiplos modelos/projetos sem alterar configurações ou usar model memory.
Visão Geral do Código: Decodificar PWM de Receptor RC com Fail-Safe
Código mede sinais PWM usando interrupções de mudança de pino (Pin Change Interrupts). Funções automatizam configuração das interrupções e extração de dados de qualquer pino digital/analógico (exceto A6/A7) no Uno, Nano ou Pro Mini. Fácil para iniciantes.
Objetivo: módulo genérico de receptor RC com fail-safe, portável entre projetos. Código de exemplo na seção "como usar" é meio para o fim.
Nota: não funciona com SoftwareSerial ou outras libs que usam pin change interrupts.
Como o Código Funciona (para interessados):
- Pinos de entrada definidos em array (qualquer tamanho).
- Função setup habilita pin change interrupts configurando registradores para cada pino do array.
- Mudança de tensão em pino selecionado dispara uma de 3 ISRs conforme registrador de porta:
ISR(PCINT0_vect)→ Port B,ISR(PCINT1_vect)→ Port C,ISR(PCINT2_vect)→ Port D. - Dentro de cada ISR: loop FOR + IFs determinam qual pino mudou e a qual canal RC pertence. Tempo do interrupt via
micros()antes de voltar aoloop(). - Intervalos entre mudanças de pino → cálculo de largura de pulso e período de repetição.
- Flags setadas em cada ISR indicam novos pulsos recebidos.
- Flags usadas pelas funções restantes para extrair/processar dados coletados pelas ISRs.
Vídeo do Joop Brokking (primeiros 8 min) explica bem uso de pin change interrupts para medir PWM de receptor RC.
Tudo isso é gerenciado por PWMread_RCfailsafe.ino (download no final).
Info sobre manipulação de portas: tronixstuff.com
Além do tratamento de interrupções, função dedicada RC_decode() converte largura de pulso (1000-2000µs) em sinal de controle ±100%. Fail-safe verifica sinal válido (tolerâncias: 10-330Hz, 500-2500µs). Se perdido, retorna valor de fail-safe pré-definido.
Valores de calibração por transmissor e posições de fail-safe por canal em PWMread_RCfailsafe.ino.
Como Usar PWMread_RCfailsafe.ino
Passo 1: Hardware Exemplo com Arduino Uno
Se seguindo exemplo com Uno, conecte receptor assim (caso contrário, pule para Passo 2):
- Alimente receptor com 5V e GND do Arduino
- Pinos de sinal do receptor → pinos 2 a 7 do Arduino (jumpers fêmea-macho). Receptor 2 canais → apenas pinos 2 e 3.
- Exemplo mixer servo: servo 1 sinal → pino 9, servo 2 → pino 10.

Passo 2: Copiar PWMread_RCfailsafe.ino para Pasta do Sketch
Sketch exemplo RC_Read_Example incluso para download. Use como sketch principal.
Copie PWMread_RCfailsafe.ino para pasta do sketch principal. Ao abrir no IDE, aparece segunda aba com o código.

Passo 3: Especificar Pinos de Entrada
Abra sketch principal no IDE. Clique aba PWMread_RCfailsafe, role até "USER DEFINED VARIABLES" e insira pinos no array pwmPIN[].
Qualquer número de pinos, qualquer ordem. Mais entradas = mais tempo na rotina de interrupção. A6/A7 são só analógicos, não servem. Arduino MEGA não suportado atualmente (fácil adicionar se houver demanda).
Primeiro elemento = canal 1, segundo = canal 2… se usar todos canais do receptor, alinhe ordem.

Passo 4: Revisar Funções Disponíveis

Passo 5: Imprimir Dados de Largura de Pulso na Serial
Carregue RC_Read_Example, ligue transmissor, imprima dados brutos.
Use RC_avail() para checar novos dados em todos canais, depois print_RCpwm() para enviar à serial.

Passo 6: Calibrar Transmissor
Use dados de print_RCpwm() para ajustar manualmente arrays RC_min[], RC_mid[], RC_max[] calibrando cada canal para ±100%.

Passo 7: Imprimir Canais Calibrados na Serial
Comente print_RCpwm(). Use RC_decode(canal) para calibrar cada canal para ±1. Imprima com decimal2percentage() + Serial.println().

Passo 8: Configurar Fail-Safe
Ajuste posições de fail-safe no array RC_failsafe[] por canal (range ±1). Ligue/desligue transmissor para testar.
Entrada RC pronta para uso no sketch.
Nota: pode precisar desativar fail-safe no receptor, senão Arduino não detecta perda de sinal.

Exibir Taxa de Quadros e Frequência do Receptor
Período e frequência de repetição do pulso do receptor podem ser impressos. Use PWM_read(número_canal) para checar novos dados no canal escolhido, depois PWM_period() e PWM_freq() para extrair dados. Exemplo em RC_FrameRate.ino.
Melhor usar canal 1 (primeiro pulso de cada quadro). PWM_read() usa mesmas flags que RC_decode(CH) — chame PWM_read() primeiro.

Período do receptor útil: diz quanto tempo o código tem antes do próximo quadro. Se RC_avail() não detectar novos dados após tempo predeterminado (ex: 21ms), rode RC_decode() para disparar fail-safe e/ou manter programa (ex: controlador PID) em frequência constante.
Implementado em RC_Read_Example.ino:
now = millis();
if(RC_avail() || now - rc_update > 21) {
rc_update = now;
// atualizar dados RC via RC_decode()
// rodar controlador PID
// aplicar mixer de servos
// posicionar servos
}
Exemplo de Mixer de Servos
Incluído RC_ServoMixer_Example.ino misturando 2 canais do receptor (canais 2 e 3: elevator e aileron). Mostra método para direção, rate e sub-trim de servos. Biblioteca Servo controla servos nos pinos 9 e 10.

Mixer: somar/subtrair canais, limitar saída a -1..+1. Duas saídas (um por servo):
mix1 = canal2 - canal3 (elv - ail)
mix2 = canal2 + canal3 (elv + ail)
Antes de posicionar servos, converter sinal ±100% (±1) para largura de pulso µs equivalente. Uso função calc_uS() no final do sketch.

Pulso neutro padrão = 1500µs, faixa normal ±500µs → min 1000µs (-100%), max 2000µs (+100%). Com rate, direção, sub-trim:
pulso µs = 1500 + (posição_servo_% * rate * direção + sub_trim) * 500
Direção, rate, sub-trim podem ser estáticos ou modificados dinamicamente pelo sketch via outro canal do receptor ou outro meio.
Racional da Abordagem
Possível ler receptor com pulseIn(PIN, HIGH), mas pulseIn() bloqueia loop() esperando pulso iniciar e terminar, desperdiçando CPU. Com múltiplas entradas, dados podem ser perdidos.
Para velocidade: pin change interrupt + manipulação direta de portas → loop() roda com atraso mínimo. Mas mais complexo que pulseIn().
Queria vantagens dos dois mundos: código genérico portável entre projetos. Basta copiar .ino (funções + rotinas ISR) para pasta do sketch principal, especificar pinos de entrada, usar funções no sketch.
Limitações
Função micros()
Timing em microssegundos usa micros() → passos de 4µs. Precisão de 4µs medindo pulsos 1000-2000µs. Praticamente adequado.
Possível melhorar para 0.5µs com timer interrupts: instructables.com
Eficiência do PWMread_RCfailsafe.ino
Lendo receptor 6 ou 9 canais: 1.4-2.0% do tempo de CPU nas rotinas ISR — aceitável.
Tempo por ISR conforme canais selecionados:
| Canais | Tempo ISR |
|---|---|
| 1 | < 8µs |
| 2 | < 12µs |
| 3 | < 16µs |
| 4 | < 20µs |
| 5 | < 20µs |
| 6 | < 24µs |
Mais canais = ISR mais lenta (loop FOR roda todos canais a cada chamada). Extra negligenciável em sinais RC baixa frequência (50Hz).
Entrada/saída ISR ~4µs. Para 1 pulso, ISR roda 2x (subida + descida).
Tempo medir 1 pulso com 6 entradas RC: 2 × (4µs + 24µs) = 56µs (largura mínima mensurável).
Ler todos 6 canais: 336µs (6 × 56µs). Período repetição receptor 20ms → ISR roda 1.68% do tempo (0.000336/0.02). Muito melhor que pulseIn() (bloqueia até 20ms por pino).
FYI: 2 entradas RC → ISR roda 0.16% do tempo.
Frequência Máxima Prática (Hz)
Para outros usos: máx prático ~2.5kHz (100 passos resolução micros() ±0.025kHz). 1 pino nessa freq → 3% tempo na interrupção → duty mínimo mensurável 0.03 = pulso mínimo 12µs. Freq maiores: reescreva ISR para sua aplicação.
Código
PWMread_RCfailsafeRC_Read_ExampleRC_FrameRateRC_ServoMixer_Example
Todos disponíveis para download. PWMread_RCfailsafe.ino contém funções, rotinas ISR, variáveis de usuário (pinos, calibração, fail-safe), variáveis globais, setup de interrupções, 3 ISRs (Port B, C, D), funções de saída RC (calibração, fail-safe, impressão), funções PWM genéricas.
Processo de manufatura
- Dominando Entrada e Saída em Programação C
- Crie Animações e Jogos Envolventes em LCD com Arduino UNO
- Construa um Voltímetro Inteligente com Arduino e Smartphone – Projeto DIY Fácil
- Registrador de Temperatura e Umidade com Arduino, DHT11 e Ethernet Shield
- Leitura de Temperatura e Umidade com DHT11 no Blynk – Tutorial Arduino Passo a Passo
- Python 3 para Arduino UNO: Controle de Comandos Fácil e Demo com LED
- Autômatos Celulares em Tempo Real no Arduino com Display OLED 128x64
- Construa um Rádio FM Compacto com Arduino Nano e RDA5807M
- Construa um Receptor FM Potente com Arduino e Módulo TEA5767
- Circuito de Entrada Analógica Isolada para Arduino