Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Ler PWM, decodificar entrada do receptor RC e aplicar à prova de falhas

Componentes e suprimentos

Arduino UNO
× 1
Micro servo motor SG90
× 2

Sobre este projeto


Este projeto contém código genérico, mas eficiente, que pode ser usado para simplesmente ler um receptor RC (ou qualquer outro sinal PWM) em qualquer pino de entrada do Arduino, e também aplicar um fail-safe no caso de perda do sinal do transmissor.

Abaixo está um vídeo mostrando um Arduino uno agindo como um servo mixer usando o código PWMread_RCfailsafe.ino disponível na parte inferior desta página.

De forma útil, as funções em PWMread_RCfailsafe.ino cuidam dos registros de interrupção para você e podem ser movidas facilmente entre diferentes projetos que usam pinos diferentes.

No exemplo de vídeo abaixo:
  • O fail-safe é ativado quando o receptor não tem sinal do transmissor. o canal do elevador está definido como cheio e o canal do aileron está definido como neutro
  • A direção do servo azul é definida pela posição do acelerador
  • A amplitude de movimento (taxas) do servo azul é definida pelo controle deslizante na lateral do transmissor
  • A mixagem é ligada e desligada usando a chave de engrenagem no transmissor





Conteúdo

  • Como os servos são controlados pelo PWM
  • Exemplos de uso do Arduino em modelos / robôs RC
  • Visão geral do código:decodifique o PWM do receptor RC com proteção contra falhas
  • Como usar PWMread_RCfailsafe.ino
  • Exibir a frequência e a taxa de quadros do receptor
  • Exemplo de mistura de servo
  • Justificativa para a abordagem adotada
  • Limitações





Como os servos e controladores de velocidade são controlados pelo PWM?


Presume-se no restante deste projeto que você tenha um entendimento dos sinais PWM usados ​​para controlar servos e controladores de velocidade. Aqui está um bom vídeo explicando como esses sinais de modulação por largura de pulso (PWM) funcionam.

Você também deve ter um conhecimento prático de:
  • O IDE Arduino
  • Variáveis ​​float, booleana e int
  • If loops
  • For loops
  • Matrizes
  • Biblioteca servo





Exemplos de uso do Arduino em modelos / robôs RC


Você só será limitado pela sua imaginação:
  • Aplicar a mistura servo, ligar / desligar as luzes, controlar bombas / válvulas, definir sequências sob medida ...
  • Crie um controlador (ou seja, estabilização de vôo / piloto automático, sustentação de rumo, sustentação de altitude / profundidade, nivelador automático, detecte e evite, volte para casa ...)
  • Faça com que seu modelo RC responda a uma perda de sinal ou baixa voltagem da bateria ...
  • Use o mesmo transmissor para vários modelos / projetos sem ter que alterar nenhuma configuração ou usar um recurso de memória de modelo.





Visão geral do código:decodifique o PWM do receptor RC com proteção contra falhas


Este código mede sinais PWM (modulação por largura de pulso) usando interrupções de mudança de pino. As funções utilizadas automatizam a configuração das interrupções e a extração de dados de qualquer pino digital ou analógico (excluindo A6 e A7), no Arduino Uno, Nano ou Pro Mini. Isso torna o código fácil de usar, mesmo para iniciantes.

O objetivo principal deste projeto era criar um receptor RC genérico com um "módulo" à prova de falhas que pudesse ser movido rapidamente entre os projetos. Como tal, o código de exemplo mostrado na seção "como usar" pode ser usado apenas como um meio para um fim.

Nota: este código não funcionará com o serial do software ou qualquer outra biblioteca que usa interrupções de mudança de pino.

Para aqueles interessados ​​em como o código funciona:
  • Os pinos de entrada são identificados em uma matriz. Esta matriz pode ter qualquer comprimento.
  • Uma função de configuração permite interrupções de mudança de pino, definindo os registros apropriados para cada pino listado na matriz de pinos.
  • Uma mudança de tensão em qualquer um dos pinos selecionados irá disparar uma das três Rotas de Serviço de Interrupção (ISR) dependendo de qual registro de porta o pino pertence a ISR (PCINT0_vect) -> Porta B, ISR (PCINT1_vect) -> Porta C ou ISR (PCINT2_vect) -> Porta D.
  • Dentro de cada ISR, um loop FOR e instruções IF são usados ​​para determinar qual pino foi alterado e a qual canal RC ele pertence. O tempo da interrupção é anotado por meio do uso de micros () antes de retornar ao loop principal ().
  • Os intervalos de tempo entre as mudanças dos pinos são usados ​​para calcular a largura do pulso e o período de repetição.
  • Sinalizadores são definidos em cada ISR para indicar quando novos pulsos foram recebidos
  • Os sinalizadores são então usados ​​pelas funções restantes para extrair e processar os dados coletados pelos ISRs

O seguinte vídeo do YouTube feito por Joop Brokking fala sobre um projeto diferente que usa o mesmo método para conectar um receptor RC ao arduino. Durante os primeiros 8 minutos, Joopclearlyexplicou como fazer use interrupções de mudança de pino para medir sinais PWM de um receptor RC.

Todos esses detalhes são cuidados por PWMread_RCfailsafe.ino que pode ser baixado no final desta página.

Algumas informações úteis sobre a manipulação de portas também podem ser encontradas aqui: https://tronixstuff.com/2011/10/22/tutorial-arduino-port-manipulation/

Além do tratamento de interrupção de mudança de pino, uma função dedicada RC_decode () foi escrita para converter uma largura de pulso (1000-2000uS) em um sinal de controle de + -100% de um transmissor. Um fail-safe verifica um sinal de transmissor válido usando as tolerâncias de sinal de 10-330 Hz e 500-2500uS. Se o sinal for perdido, RC_decode () retorna um valor predeterminado à prova de falhas.

Os valores de calibração para um transmissor específico e as posições à prova de falhas podem ser definidas para cada canal em PWMread_RCfailsafe.ino





Como usar PWMread_RCfailsafe.ino


Etapa 1: Exemplo hardware configuração com Arduino Uno

Se seguir o exemplo de configuração com um Arduino Uno, conecte seu receptor da seguinte maneira:(caso contrário, se estiver usando seu próprio projeto, pule direto para a etapa 2)
  • Ligue o receptor usando os pinos 5v e GND
  • Conecte os pinos de sinal do receptor aos pinos 2 a 7 no Arduino usando fios de jumper fêmea para macho. (Se você tiver um receptor de 2 canais, conecte-se apenas aos pinos 2 e 3)
  • Para o exemplo do servo mixer, conecte um fio de sinal do servo ao pino 9 e o outro ao pino 10.

Etapa 2:Copie PWMread_RCfailsafe.ino para a pasta de desenho

Um esboço de exemplo RC_Read_Example foi incluído para download na parte inferior da página. Você pode usar isso como seu esboço principal ao seguir as etapas abaixo.

Copie e cole o arquivo PWMread_RCfailsafe.ino na pasta que contém seu esboço principal. Na próxima vez que você abrir o esboço no IDE, uma segunda guia aparecerá contendo o código em PWMread_RCfailsafe.ino.

Etapa 3:Especifique o entrada alfinetes

Abra ou reabra o esboço principal no IDE do Arduino.

Clique na guia PWMread_RCfailsafe, role para baixo até o título "VARIÁVEIS DEFINIDAS PELO USUÁRIO" e insira os pinos de entrada na matriz pwmPIN [].

Nota: Qualquer número de pinos pode ser usado e em qualquer ordem. Esteja ciente de que quanto mais entradas você tiver, mais tempo o código gastará abordando a rotina de interrupção. Nota A6 e A7 são apenas pinos analógicos e não podem ser usados.

O Arduino MEGA não é compatível atualmente, no entanto, isso poderia ser facilmente remediado se houvesse vontade de usá-lo.

Nota: o primeiro elemento em pwmPIN [] é o canal 1, o segundo elemento é o canal 2, etc ... se você está usando todos os canais do receptor, seria uma boa ideia certificar-se de que os canais 1 do receptor correspondem ao canal 1 em pwmPIN [] ...

Etapa 4: Rever o disponível funções em PWMread_RCfailsafe.ino

Etapa 5: Imprimir o pulso largura dados para serial

Carregue o código RC_Read_Example, ligue o transmissor e imprima os dados brutos de largura de pulso em serial.

A função RC_avail () deve ser usada para verificar quando novos dados foram recebidos em todos os canais, e então usar print_RCpwm () para enviar os dados de largura de pulso para serial.

Etapa 6: Calibre o transmissor

Usando os dados de largura de pulso impressos em serial via print_RCpwm () para modificar manualmente os valores nas matrizes RC_min [], RC_mid [] e RC_max [] para calibrar cada canal no intervalo + -100%.

Etapa 7:Imprima os canais calibrados para serial

Comente a função print_RCpwm ()

Use a função RC_decode (canal) para calibrar cada canal na faixa + -1.

Em seguida, imprima cada um dos canais calibrados em serial usando a função decimal2percentage () seguida por Serial.println ("")

Etapa 8: Defina o fail-safe

Ajuste as posições de segurança contra falhas na matriz RC_failsafe [] para cada canal (na faixa + -1).

Ligue e desligue o transmissor para verificar se a proteção contra falhas opera conforme desejado.

A entrada RC agora pode ser usada em seu esboço.

Nota: você pode ter que desativar qualquer recurso de segurança contra falhas no receptor, caso contrário, o arduino não será capaz de responder à perda do sinal do transmissor.





Exibir a taxa de quadros e frequência do receptor


O período de repetição do pulso do receptor e a frequência podem ser impressos em serial. Verifique se os novos dados estão disponíveis no canal escolhido usando a função PWM_read (número do canal), antes de usar PWM_period () e PWM_freq () para extrair os dados para impressão. O código de exemplo está disponível em RC_FrameRate.ino.

É melhor usar o primeiro canal, pois este será o primeiro pulso enviado em cada quadro do receptor. PWM_read () usa os mesmos sinalizadores que RC_decode (CH), então certifique-se de que PWM_read () seja chamado primeiro.

Veja a imagem abaixo:

O período do receptor pode ser útil para saber quanto tempo o código tem antes que o próximo conjunto de dados chegue. Se RC_avail () não detectar novos dados RC após um tempo predeterminado, ou seja, 21 ms, execute RC_decode () a fim de acionar o fail-safe e / ou continuar a executar o programa (que poderia ser um controlador PID) em uma frequência constante.

Isso é obtido no RC_Read_Example.ino pela seguinte instrução if.
  now =millis (); if (RC_avail () || now - rc_update> 21) rc_update =now; // atualize os dados de entrada RC usando RC_decode () // execute um controlador PID // aplique a mistura de servo // posicione os servos}  





Exemplo de mistura de servo


Incluí RC_ServoMixer_Example.ino para mostrar como você pode mixar dois canais de receptor (neste caso, os canais 2 e 3, profundor e aileron). O esboço também mostra um método para definir a direção, taxa e sub trim do servo. A biblioteca de servo é usada para controlar os servos por meio dos pinos 9 e 10.

Abaixo está uma captura de tela da seção de mistura de servo do código:

A mixagem é obtida simplesmente adicionando e subtraindo os dois canais juntos e limitando a saída na faixa de -1 a +1. Ao aplicar a mistura de profundor e aileron, você cria duas saídas, uma para cada servo.

mix1 =canal 2 - canal 3 (elv - ail)

mix2 =canal 2 + canal3 (elv - ail)

Antes de posicionar os servos, você precisará converter o sinal de + -100% (+ -1) para uma largura de pulso equivalente em microssegundos para o servo. No RC_ServoMixer_Example.ino eu uso uma função calc_uS () para fazer isso. Esta função é colocada na parte inferior do esboço e é mostrada na captura de tela abaixo.

A direção, taxa e sub trim especificados para cada servo são usados ​​para calcular uma largura de pulso apropriada para o servo.

O pulso neutro padrão é 1500uS, e a faixa normal de ambos os lados do neutro é + -500uS. Isso dá uma largura de pulso mínima de 1000uS (-100%) e máxima de 2000uS (+ 100%). O pulso com taxas, direção e sub trim aplicados podem, portanto, ser calculados como segue.

pulso, uS =1500 + (servo_position_% * taxas * direção + sub trim) * 500

A direção do servo, taxa e sub trim podem ser estáticos ou modificados dinamicamente pelo esboço em resposta a uma entrada de outro canal receptor ou por algum outro meio.





Justificativa para a abordagem adotada


É possível ler um receptor RC usando a função pulseIn (PIN, HIGH), porém pulseIn () bloqueia o código em loop () enquanto espera que um pulso comece e depois termine, desperdiçando um precioso tempo de processamento. Se houver mais de uma entrada, os dados também podem ser perdidos.

Para velocidade, é melhor usar o recurso de interrupção de mudança de pino do Arduino junto com a manipulação direta da porta para permitir que o código em loop () seja executado com o mínimo de atraso. No entanto, isso é mais complexo e demorado do que simplesmente chamar pulseIn (PIN, HIGH).

Portanto, eu queria obter as vantagens dos dois mundos, escrevendo algum código genérico que pudesse mover entre os projetos. Tudo o que é necessário é copiar e colar um arquivo.ino (contendo as funções e rotinas de interrupção) na pasta de esboço principal, especificar os pinos de entrada e, em seguida, usar as funções no esboço.





Limitações


O função micros ()

O tempo de microssegundo no arduino é executado usando a função micros (). Esta função conta em etapas 4uS. Isso significa que temos um nível de precisão de 4 microssegundos quando medimos os pulsos de 1000-2000uS. Do ponto de vista prático, isso é mais do que adequado.

Se desejado, é possível melhorar esta resolução para 0,5uS usando interrupções do temporizador. veja o link abaixo:

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

Eficiência de PWMread_RCfailsafe.ino

Se você estiver usando PWMread_RCfailsafe.ino para ler um receptor de 6 ou 9 canais, 1,4-2,0% do tempo de processamento é gasto executando as rotinas de interrupção de mudança de pino, o que eu diria que é mais do que aceitável.

No entanto, é sempre bom entender as limitações do código e como ele pode ser acelerado, se necessário.

Abaixo está uma lista do tempo que leva para executar cada ISR dependendo do número de canais de entrada selecionados.

1 canal <8uS

2 canais <12uS

3 canais <16uS

4 canais <20uS

5 canais <20uS

6 canais <24uS

Nota: quanto mais canais usados, mais tempo cada ISR leva para ser executado. Isso ocorre porque há loopruns em cada canal sempre que o ISR é chamado.

Este tempo extra (ineficiência) é insignificante ao medir sinais RC de baixa frequência (ou seja, 50 Hz).

Além disso, leva ~ 4uS para entrar e sair de um ISR. Para um pulso, o ISR é executado duas vezes, uma vez no início de um pulso (BAIXO para ALTO) e novamente no final (ALTO para BAIXO).

O tempo necessário para medir 1 pulso ao usar 6 entradas RC é

2 * (4us para inserir ISR + 24uS para executar ISR) =2 * 28 =48uS.

Nota: esta é a largura de pulso mínima que pode ser medida.

O tempo gasto para ler todos os 6 canais é 288uS (6 * 48uS)

Supondo que o período de repetição do receptor seja de 20 milissegundos, a interrupção será executada por 1,44% (0,000288 / 0,02) do tempo. Isso é significativamente melhor do que usar a função pulseIn (). pulseIn () bloquearia o código por até 20 milissegundos para cada pino.

Para sua informação: se o arduino tiver apenas 2 entradas RC, o ISR será executado por apenas 0,16% do tempo (0,000032 / 0,02)

Frequência prática máxima ( Hz)

Se usar este código para qualquer outro propósito, sugiro que a frequência máxima prática seja 2,5kHz. Isso dá 100 etapas de resolução da função micros () (+ - 0,025 kHz).

Se estiver usando um pino de entrada nesta frequência, 3% do tempo é gasto na interrupção, o que significa que a tarefa mínima que pode ser medida é 0,03. Isso equivale a um pulso mínimo de 12 µS.

Para frequências mais altas, reescreva o ISR de acordo com sua aplicação.

Código

  • PWMread_RCfailsafe
  • RC_Read_Example
  • RC_FrameRate
  • RC_ServoMixer_Example
PWMread_RCfailsafe Arduino
Este arquivo .ino contém as funções e rotinas de interrupção de mudança de pino (ISR) usadas para decodificar um receptor RC e aplicar um fail safe se o sinal do transmissor for perdido. Copie e cole este arquivo na mesma pasta do esboço principal (ao abrir o esboço, este código aparecerá como uma segunda guia no IDE do arduino). Em seguida, siga as instruções no arquivo.
 / * Kelvin Nelson 24/07/2019 * * Decodificação de modulação por largura de pulso (PWM) do receptor RC com proteção contra falhas * * Este código contém funções fáceis de usar para medir sinais de onda quadrada em qualquer arduiuno pro mini, nano ou uno pins, excluindo A6 e A7. * O código deve ser usado com receptores RC, mas também pode ser usado na maioria das outras aplicações de medição PWM como um substituto direto para pulseIn (PIN, HIGH). * (até o momento ele não foi testado em uma frequência maior que 1 khz ou em um megacontrole) * * Um pulso de sinal RC pode ser convertido de uma duração de largura de pulso (1000-2000uS) em cada pino de entrada em um - + 100 % (- + 1,0) saída para uso em um esboço. * A calibração para esta conversão mais uma configuração à prova de falhas pode ser definida para cada canal. (tolerâncias à prova de falhas de 10-330 Hz e 500-2500uS). * * Os dados brutos para cada pino também podem ser extraídos, ou seja, tempo de pulso, largura de pulso, comprimento do quadro, dever e frequência. * * A configuração é rápida, a organização deste arquivo é a seguinte:* * - Visão geral do código * - Lista de funções * - Como usar, incluindo esboços de exemplo * - Variáveis ​​definidas pelo usuário -> especificar pinos de entrada, transmissor calibração e à prova de falhas. * - Variáveis ​​globais e funções * * VISÃO GERAL DO CÓDIGO:* * O código ativa interrupções de mudança de pino nos pinos selecionados, definindo os registros apropriados. * * Uma mudança de tensão em qualquer um dos pinos selecionados acionará uma das três Rotinas de Serviço de Interrupção, dependendo de qual registro o pino pertence. * - ISR (PCINT0_vect), ISR (PCINT1_vect) ou ISR (PCINT2_vect) * * Dentro de cada ISR, o código determina qual pino foi alterado e faz uma anotação do tempo antes de retornar ao loop principal (). * * Os intervalos de tempo entre as mudanças de pino são usados ​​para calcular a largura de pulso e o comprimento do quadro. * * Os sinalizadores são definidos pelo ISR para indicar quando novos pulsos são recebidos. * * Os sinalizadores são então usados ​​para extrair e processar os dados coletados por cada ISR. * * Embora não seja exatamente o mesmo, este código segue princípios semelhantes aos explicados neste vídeo:https://youtu.be/bENjl1KQbvo * * /// LISTA DE FUNÇÕES:// TIPO DE SAÍDA NOME DE NOTAS DE FUNÇÃO // void setup_pwmRead () inicializa a medição PWM usando interrupções de mudança de pino // DECODIFICAÇÃO DO RECEPTOR RC // O booleano RC_avail () retorna um ALTO quando novos dados RC estão disponíveis // float RC_decode (número do canal) decodifica o canal RC selecionado no intervalo + -100 %, e aplica um failafe.// void print_RCpwm () Imprime os dados brutos do canal RC na porta serial (usada para calibração) .// GENERIC PWM MEASUREMENTS // boolean PWM_read (número do canal) retorna um HIGH quando um novo pulso foi detectado em um canal específico. // A função salva os dados do pulso em variáveis ​​fora das rotinas de interrupção // e deve ser chamada antes de usar o resto das funções PWM.// Unsigned long PWM_time () retorna o tempo no início do pulso // float PWM () retorna a largura do pulso // float PWM_period () retorna o tempo entre os pulsos // float PWM_freq () calcula a frequência // float PWM_duty () calcula o dever // NOTA:PWM_read (CH) e RC_decode (CH) usam os mesmos sinalizadores para detectar quando novos dados estão disponíveis, o que significa que os dados podem ser perdidos se ambos forem usados ​​no mesmo canal ao mesmo tempo.// SUGESTÃO:se você quiser usar PWM_read (CH) para encontrar a taxa de quadros de um canal RC, chame-o antes de RC_decode (CH). A saída de RC_decode (CH) será então padronizada para failafe.// COMO USAR, incluindo esboços de exemplo // sob o título "VARIÁVEIS DEFINIDAS PELO USUÁRIO" no código abaixo://// Etapa 1:insira os pinos de entrada em a matriz pwmPIN [] ={}. //// - Qualquer número de pinos pode ser inserido em pwmPIN [] (pinos disponíveis 0 - 13 e A0 - A5) // - Os pinos não precisam estar em ordem numérica, por exemplo pwmPIN [] ={A0, 5,6,10,8} para 5 canais, ou pwmPIN [] ={A0,5} para 2 canais // - O primeiro elemento na matriz é o número do pino para "canal 1" e o segundo é o pino número para "canal 2" ... etc.// - Todos os pinos conectados ao receptor RC precisam estar no início do array. ou seja, os primeiros 2 canais podem ser entradas RC e o terceiro canal pode ser conectado a outro dispositivo como o pino de eco de um sensor ultrassônico.//// Etapa 2:se um receptor RC estiver conectado a todas as entradas, defina RC_inputs para 0, se não, especifique o número de canais conectados ao receptor, ou seja, RC_inputs =2; //// Etapa 3:calibre seu transmissor enviando um esboço simples com este arquivo .ino incluído na pasta de esboço e imprima os valores PWM brutos para serial (como alternativa, copie e cole as funções necessárias no esboço) .// Usando as informações do monitor serial, atualize manualmente os valores nas matrizes RC_min [], RC_mid [], RC_max [] para se adequar ao seu transmissor (use taxas totais para obter a melhor resolução). // um esboço de exemplo para imprimir os dados PWM do canal RC em serial. / * void setup () {setup_pwmRead (); Serial.begin (9600); } void loop () {if (RC_avail ()) print_RCpwm (); } * /// Etapa 4:Escolha uma posição à prova de falhas para cada canal, no intervalo de -1,0 a +1,0, e insira-a na matriz RC_failsafe [] ={} // Observação:se você deseja que o arduino responda a perda de sinal do transmissor pode ser necessário desativar o recurso de proteção contra falhas em seu receptor (se houver) .// um esboço de exemplo para verificar a operação da proteção contra falhas e para imprimir os canais calibrados em serial:/ * unsigned long now; // variáveis ​​de tempo para atualizar os dados em um intervalo regular unsigned long rc_update; canais int constantes =6; // especifica o número de canais do receptor float RC_in [canais]; // um array para armazenar a entrada calibrada do receptor void setup () {setup_pwmRead (); Serial.begin (9600); } void loop () {agora =millis (); if (RC_avail () || now - rc_update> 25) {// se os dados RC estão disponíveis ou 25ms se passaram desde a última atualização (ajuste para se adequar à taxa de quadros do receptor) rc_update =now; // print_RCpwm (); // descomente a impressão de dados brutos do receptor para serial para (int i =0; i  =0 &&pwmPIN [i] <=7) pwmPIN_port [i] =2; // pino pertence a PCINT2_vect (PORT D) else if (pwmPIN [i]> =8 &&pwmPIN [i] <=13) pwmPIN_port [i] =0; // o pino pertence a PCINT0_vect (PORTA B) // converte o número do pino (ou seja, pino 11 ou pino A0) para a posição do pino no registro da porta. É mais provável que haja uma maneira melhor de fazer isso usando uma macro ... // (Ler o estado do pino diretamente dos registradores da porta acelera o código no ISR) if (pwmPIN [i] ==0 || pwmPIN [i ] ==A0 || pwmPIN [i] ==8) pwmPIN_reg [i] =0b00000001; else if (pwmPIN [i] ==1 || pwmPIN [i] ==A1 || pwmPIN [i] ==9) pwmPIN_reg [i] =0b00000010; else if (pwmPIN [i] ==2 || pwmPIN [i] ==A2 || pwmPIN [i] ==10) pwmPIN_reg [i] =0b00000100; else if (pwmPIN [i] ==3 || pwmPIN [i] ==A3 || pwmPIN [i] ==11) pwmPIN_reg [i] =0b00001000; else if (pwmPIN [i] ==4 || pwmPIN [i] ==A4 || pwmPIN [i] ==12) pwmPIN_reg [i] =0b00010000; else if (pwmPIN [i] ==5 || pwmPIN [i] ==A5 || pwmPIN [i] ==13) pwmPIN_reg [i] =0b00100000; else if (pwmPIN [i] ==6) pwmPIN_reg [i] =0b01000000; else if (pwmPIN [i] ==7) pwmPIN_reg [i] =0b10000000; }} // CONFIGURAÇÃO DE INTERRUPTS DE MUDANÇA DE PIN evite setup_pwmRead () {for (int i =0; i  num_ch) RC_inputs =num_ch; // define o número de pinos conectados a um receptor RC. } // INTERRUPT SERVICE ROUTINES (ISR) USADO PARA LER PWM INPUT // o PCINT0_vect (registro da porta B) reage a qualquer mudança nos pinos D8-13.// o PCINT1_vect (registro da porta C) "" "" A0-A5. // os registros de porta PCINT2_vect (registrador de porta D) "" "" D0-7.// são usados ​​para acelerar instruções if no código 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 // LER INTERRUPÇÕES NOS PINOS D8-D13:A rotina ISR detecta qual pino foi alterado e retorna a largura de pulso PWM e o período de repetição de pulso. ISR (PCINT0_vect) {// esta função será executada se uma mudança de pino for detectada na porta B 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]; interrupções (); } 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;}

Esquemas

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

Processo de manufatura

  1. C - Entrada e Saída
  2. Animação de LCD e jogos
  3. Faça você mesmo voltímetro usando Arduino e Smartphone
  4. Registrador de dados de temperatura e umidade
  5. Como ler a temperatura e umidade em Blynk com DHT11
  6. Comunicação Python3 e Arduino
  7. Arduino e autômatos celulares baseados em OLED
  8. Rádio FM usando Arduino e RDA8057M
  9. Receptor de rádio FM Arduino TEA5767
  10. Uma entrada analógica isolada para Arduino