Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Lire le PWM, décoder l'entrée du récepteur RC et appliquer la sécurité intégrée

Composants et fournitures

Arduino UNO
× 1
Micro-servomoteur SG90
× 2

À propos de ce projet

Ce projet contient un code générique mais efficace qui peut être utilisé pour simplement lire un récepteur RC (ou tout autre signal PWM) sur n'importe quelle broche d'entrée Arduino, et également appliquer une sécurité intégrée en cas de perte du signal de l'émetteur.

Vous trouverez ci-dessous une vidéo montrant un Arduino uno agissant comme un servomélangeur à l'aide du code PWMread_RCfailsafe.ino disponible en bas de cette page.

Les fonctions de PWMread_RCfailsafe.ino s'occupent des registres d'interruption pour vous et peuvent être facilement déplacées entre différents projets utilisant différentes broches.

Dans l'exemple vidéo ci-dessous :

  • La sécurité intégrée s'active lorsque le récepteur n'a aucun signal de l'émetteur. le canal de profondeur est réglé au maximum et le canal des ailerons est réglé au neutre
  • La direction du servo bleu est définie par la position de l'accélérateur
  • La plage de mouvement (taux) du servo bleu est définie par le curseur sur le côté de l'émetteur
  • Le mixage est activé et désactivé à l'aide du commutateur de vitesse sur l'émetteur

Sommaire

  • Comment les servos sont-ils contrôlés par PWM
  • Exemples d'utilisation d'Arduino dans les modèles/robots RC
  • Aperçu du code :décoder le PWM du récepteur RC avec sécurité intégrée
  • Comment utiliser PWMread_RCfailsafe.ino
  • Afficher la fréquence d'images et la fréquence du récepteur
  • Exemple de mixage servo
  • Raison d'être de l'approche adoptée
  • Restrictions

Comment les servos et les contrôleurs de vitesse sont-ils contrôlés par PWM ?

Il est supposé dans le reste de ce projet que vous avez une compréhension des signaux PWM utilisés pour contrôler les servos et les contrôleurs de vitesse. Voici une bonne vidéo expliquant le fonctionnement de ces signaux de modulation de largeur d'impulsion (PWM).

Vous devez également avoir une connaissance pratique de :

  • L'IDE Arduino
  • Variables flottantes, booléennes et int
  • Si boucles
  • Pour les boucles
  • Tableaux
  • Bibliothèque de servos

Exemples d'utilisation d'Arduino dans les modèles / robots RC

Vous ne serez limité que par votre imagination :

  • Appliquer le mélange servo, allumer/éteindre les lumières, contrôler les pompes/vannes, définir des séquences sur mesure...
  • Créez un contrôleur (c'est-à-dire stabilisation de vol/pilote automatique, maintien de cap, maintien d'altitude/profondeur, nivellement automatique, détection et évitement, retour à la maison...)
  • Demandez à votre modèle RC de réagir à une perte de signal ou à une tension de batterie faible...
  • Utilisez le même émetteur pour plusieurs modèles/projets sans avoir à modifier les paramètres ou à utiliser une fonction de mémoire de modèle.

Présentation du code :décoder le PWM du récepteur RC avec sécurité intégrée

Ce code mesure les signaux PWM (Pulse Width Modulation) à l'aide d'interruptions de changement de broche. Les fonctions utilisées automatisent la mise en place des interruptions et l'extraction des données de n'importe quelle broche numérique ou analogique (hors A6 et A7), sur Arduino Uno, Nano ou Pro Mini. Cela rend le code facile à utiliser même pour les débutants.

L'objectif principal de ce projet était de créer un récepteur RC générique avec un "module" à sécurité intégrée qui peut être rapidement déplacé entre les projets. En tant que tel, l'exemple de code présenté dans la section « comment utiliser » peut simplement être utilisé comme un moyen pour parvenir à une fin.

Remarque : ce code ne fonctionnera pas avec le logiciel série ou toute autre bibliothèque qui utilise des interruptions de changement de broche.

Pour ceux qui s'intéressent au fonctionnement du code :

  • Les broches d'entrée sont identifiées dans un tableau. Ce tableau peut avoir n'importe quelle longueur.
  • Une fonction de configuration permet les interruptions de changement de broche en définissant les registres appropriés pour chaque broche répertoriée dans le tableau de broches.
  • Un changement de tension sur l'une des broches sélectionnées déclenchera l'une des trois routes de service d'interruption (ISR) en fonction du registre de port auquel la broche appartient ISR(PCINT0_vect) -> Port B, ISR(PCINT1_vect) -> Port C ou ISR(PCINT2_vect) -> Port D.
  • Dans chaque ISR, une boucle FOR et des instructions IF sont utilisées pour déterminer quelle broche a changé et à quel canal RC elle appartient. L'heure de l'interruption est notée via l'utilisation de micros() avant de revenir à la boucle principale().
  • Les intervalles de temps entre les changements de broche sont utilisés pour calculer la largeur d'impulsion et la période de répétition.
  • Des drapeaux sont placés dans chaque ISR pour indiquer quand de nouvelles impulsions ont été reçues
  • Les drapeaux sont ensuite utilisés par les fonctions restantes pour extraire et traiter les données collectées par les ISR

La vidéo YouTube suivante réalisée par Joop Brokking parle d'un projet différent qui utilise la même méthode pour connecter un récepteur RC à arduino. Pendant les 8 premières minutes, Joopexplique clairement comment faire utilisez les interruptions de changement de broche pour mesurer les signaux PWM d'un récepteur RC.

Tous ces détails sont pris en charge par PWMread_RCfailsafe.ino qui peut être téléchargé au bas de cette page.

Des informations utiles sur la manipulation des ports peuvent également être trouvées ici : https://tronixstuff.com/2011/10/22/tutorial-arduino-port-manipulation/

En plus de la gestion des interruptions de changement de broche, une fonction dédiée RC_decode() a été écrite pour convertir une largeur d'impulsion (1000-2000uS) en un signal de contrôle de +-100 % à partir d'un émetteur. Une sécurité intégrée vérifie un signal d'émetteur valide en utilisant les tolérances de signal de 10 à 330 Hz et de 500 à 2 500 uS. Si le signal est perdu, alors RC_decode() renvoie une valeur de sécurité prédéfinie.

Les valeurs d'étalonnage pour un émetteur spécifique et les positions de sécurité peuvent être définies pour chaque canal dans PWMread_RCfailsafe.ino

Comment utiliser PWMread_RCfailsafe.ino

Étape 1 : Exemple matériel configuration avec Arduino Uno

Si vous suivez l'exemple de configuration avec un Arduino Uno, connectez votre récepteur comme suit :(sinon, si vous utilisez votre propre projet, passez directement à l'étape 2)

  • Alimentation du récepteur à l'aide des broches 5v et GND
  • Connectez les broches de signal du récepteur aux broches 2 à 7 de l'Arduino à l'aide de cavaliers femelles à mâles. (Si vous avez un récepteur à 2 canaux, connectez-vous uniquement aux broches 2 et 3)
  • Pour l'exemple du servo-mélangeur, attachez un fil de signal d'asservissement à la broche 9 et l'autre à la broche 10.

Étape 2 :Copiez PWMread_RCfailsafe.ino dans le dossier de croquis

Un exemple de croquis RC_Read_Example a été inclus pour téléchargement au bas de la page. Vous pouvez l'utiliser comme croquis principal en suivant les étapes ci-dessous.

Copiez et collez le fichier PWMread_RCfailsafe.ino dans le dossier contenant votre croquis principal. Lors de la prochaine ouverture de l'esquisse dans l'IDE, un deuxième onglet apparaîtra contenant le code dans PWMread_RCfailsafe.ino.

Étape 3 :Précisez le saisie épingles

Ouvrez ou rouvrez l'esquisse principale dans l'IDE Arduino.

Cliquez sur l'onglet PWMread_RCfailsafe, faites défiler jusqu'au titre "VARIABLES DÉFINIES PAR L'UTILISATEUR" et entrez les broches d'entrée dans le tableau pwmPIN[].

Remarque : N'importe quel nombre de broches peut être utilisé, et dans n'importe quel ordre. Sachez simplement que plus vous avez d'entrées, plus le code passera de temps à traiter la routine d'interruption. Remarque A6 et A7 sont des broches analogiques uniquement et ne peuvent pas être utilisées.

L'Arduino MEGA n'est actuellement pas pris en charge, mais cela pourrait être facilement résolu s'il y avait de l'appétit pour cela.

Remarque : le premier élément de pwmPIN[] est le canal 1, le deuxième élément le canal 2, etc... si vous utilisez tous les canaux du récepteur, ce serait une bonne idée de vous assurer que les canaux du récepteur 1 correspondent au canal 1 dans pwmPIN[]...

Étape 4 : Révision le disponible fonctions dans PWMread_RCfailsafe.ino

Étape 5 : Imprimer le impulsion largeur données à série

Téléchargez le code RC_Read_Example, allumez votre émetteur et imprimez les données brutes de largeur d'impulsion en série.

La fonction RC_avail() doit être utilisée pour vérifier quand de nouvelles données ont été reçues sur tous les canaux, puis utilisez print_RCpwm() pour envoyer les données de largeur d'impulsion au série.

Étape 6 : Calibrer l'émetteur

Utilisation des données de largeur d'impulsion imprimées en série via print_RCpwm() pour modifier manuellement les valeurs dans les tableaux RC_min[], RC_mid[] et RC_max[] afin de calibrer chaque canal dans la plage +-100 %.

Étape 7 : Imprimez les canaux calibrés à série

Commentez la fonction print_RCpwm()

Utilisez la fonction RC_decode(channel) pour calibrer chaque canal dans la plage +-1.

Ensuite, imprimez chacun des canaux calibrés en série à l'aide de la fonction decimal2percentage() suivie de Serial.println("")

Étape 8 : Définir la sécurité intégrée

Ajustez les positions de sécurité dans le tableau RC_failsafe[] pour chaque canal (dans la plage +-1).

Allumez et éteignez l'émetteur pour vérifier que la sécurité intégrée fonctionne comme vous le souhaitez.

L'entrée RC peut maintenant être utilisée dans votre croquis.

Remarque : vous devrez peut-être désactiver toute fonction de sécurité intégrée dans le récepteur, sinon l'arduino ne pourra pas répondre à la perte du signal de l'émetteur.

Afficher la fréquence d'images et la fréquence du récepteur

La période de répétition des impulsions du récepteur et la fréquence peuvent être imprimées en série. Vérifiez que de nouvelles données sont disponibles sur le canal choisi en utilisant la fonction PWM_read(numéro de canal), avant d'utiliser PWM_period() et PWM_freq() pour extraire les données pour l'impression. Un exemple de code est disponible dans RC_FrameRate.ino.

Il est préférable d'utiliser le premier canal car ce sera la première impulsion envoyée dans chaque trame de réception. PWM_read() utilise les mêmes indicateurs que RC_decode(CH) alors assurez-vous que PWM_read() est appelé en premier.

Voir la capture d'écran ci-dessous :

La période de réception peut être utile à connaître car elle vous indique le temps dont dispose le code avant l'arrivée de la prochaine série de données. Si RC_avail () ne détecte pas de nouvelles données RC après un temps prédéterminé, c'est-à-dire 21 ms, exécutez RC_decode () afin de déclencher la sécurité intégrée et/ou de continuer à exécuter le programme (qui pourrait être un contrôleur PID) à une fréquence constante.

Ceci est réalisé dans le RC_Read_Example.ino par l'instruction if suivante.

now =millis();if(RC_avail() || now - rc_update> 21) rc_update =now; // mettre à jour les données d'entrée RC à l'aide de RC_decode() // exécuter un contrôleur PID // appliquer le mixage des servos // positionner les servos} 

Exemple de mixage servo

J'ai inclus RC_ServoMixer_Example.ino pour montrer comment vous pouvez mélanger deux canaux de réception (dans ce cas, les canaux 2 et 3, la profondeur et l'aileron). Le croquis montre également une méthode de réglage de la direction, de la vitesse et du sous-trim du servo. La bibliothèque de servos est utilisée pour contrôler les servos via les broches 9 et 10.

Vous trouverez ci-dessous une capture d'écran de la section de mixage servo du code :

Le mixage est obtenu en ajoutant et en soustrayant simplement les deux canaux ensemble, et en limitant la sortie à la plage -1 à +1. Lorsque vous appliquez un mixage de profondeur et d'aileron, vous créez deux sorties, une pour chaque servo.

mix1 =canal 2 - canal3 (elv - ail)

mix2 =canal 2 + canal3 (elv - ail)

Avant de positionner les servos, vous devrez convertir le signal +-100% (+-1) en une largeur d'impulsion équivalente en microsecondes pour le servo. Dans le RC_ServoMixer_Example.ino, j'utilise une fonction calc_uS() pour ce faire. Cette fonction est placée au bas du croquis et est montrée dans la capture d'écran ci-dessous.

La direction, le taux et le sous-trim spécifiés pour chaque servo sont utilisés pour calculer une largeur d'impulsion appropriée pour le servo.

L'impulsion neutre standard est de 1500uS et la plage normale de chaque côté du neutre est de +-500uS. Cela donne une largeur d'impulsion min de 1000uS (-100%) et max de 2000uS (+100%). L'impulsion avec les taux, la direction et le sous-trim appliqués peut donc être calculée comme suit.

impulsion, uS =1500 + (servo_position_% * taux * direction + sous-trim) * 500

La direction, le taux et le sous-trim du servo peuvent être statiques ou modifiés dynamiquement par l'esquisse en réponse à une entrée d'un autre canal de réception, ou par d'autres moyens.

Justification de l'approche adoptée

Il est possible de lire un récepteur RC à l'aide de la fonction pulseIn(PIN, HIGH), cependant pulseIn() bloque le code en boucle() en attendant qu'une impulsion démarre puis se termine, ce qui fait perdre un temps de traitement précieux. S'il y a plus d'une entrée, les données peuvent également être perdues.

Pour la vitesse, il est préférable d'utiliser la fonction d'interruption de changement de broche de l'Arduino avec la manipulation directe du port pour permettre au code en boucle () de s'exécuter avec le minimum de retard. Cependant, cela est plus complexe et prend plus de temps que d'appeler simplement pulseIn(PIN, HIGH).

Par conséquent, je voulais profiter des avantages des deux mondes en écrivant du code générique que je peux déplacer entre les projets. Tout ce qui est nécessaire est de copier et coller un fichier .ino (contenant les fonctions et les routines d'interruption) dans le dossier de croquis principal, de spécifier les broches d'entrée, puis d'utiliser les fonctions dans le croquis.

Limites

Le fonction micros()

Le minutage de la microseconde sur l'arduino est effectué à l'aide de la fonction micros(). Cette fonction compte par pas de 4uS. Cela signifie que nous avons un niveau de précision de 4 microsecondes lorsque nous mesurons les impulsions 1000-2000uS. D'un point de vue pratique, c'est plus que suffisant.

Si vous le souhaitez, il est possible d'améliorer cette résolution à 0,5 µS en utilisant des interruptions de minuterie. voir le lien ci-dessous :

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

Efficacité de PWMread_RCfailsafe.ino

Si vous utilisez PWMread_RCfailsafe.ino pour lire un récepteur à 6 ou 9 canaux, 1,4 à 2,0% du temps de traitement est consacré à l'exécution des routines d'interruption de changement de broche, ce qui, à mon avis, est plus qu'acceptable.

Cependant, il est toujours trop bon de comprendre les limites du code et comment il pourrait être accéléré si nécessaire.

Vous trouverez ci-dessous une liste du temps nécessaire pour exécuter chaque ISR en fonction du nombre de canaux d'entrée sélectionnés.

1 canal <8uS

2 canaux <12uS

3 canaux <16uS

4 canaux <20uS

5 canaux <20uS

6 canaux <24uS

Remarque : plus il y a de canaux utilisés, plus chaque ISR met de temps à s'exécuter. C'est parce qu'une boucle for traverse chaque canal chaque fois que l'ISR est appelé.

Ce temps supplémentaire (inefficacité) est négligeable lors de la mesure de signaux RC à basse fréquence (c'est-à-dire 50 Hz).

En plus de ce qui précède, il faut ~4uS pour entrer et sortir d'un ISR. Pour une impulsion, l'ISR s'exécute deux fois, une fois au début d'une impulsion (FAIBLE à ÉLEVÉ), puis à nouveau à la fin (ÉLEVÉE à FAIBLE).

Le temps nécessaire pour mesurer 1 impulsion lors de l'utilisation de 6 entrées RC est de

2 * (4us pour entrer ISR + 24uS pour exécuter ISR) =2 * 28 =48uS.

Remarque : il s'agit de la largeur d'impulsion minimale pouvant être mesurée.

Le temps nécessaire pour lire les 6 canaux est de 288uS (6 * 48uS)

En supposant que la période de répétition du récepteur est de 20 millisecondes, l'interruption s'exécutera pendant 1,44 % (0,000288/0,02) du temps. C'est nettement mieux que d'utiliser la fonction pulseIn(). pulseIn() bloquerait le code jusqu'à 20 millisecondes pour chaque broche.

Pour info : si l'arduino n'avait que 2 entrées RC, l'ISR ne fonctionnera que 0,16% du temps (0,00032/0,02)

Fréquence maximale pratique (Hz)

Si vous utilisez ce code à d'autres fins, je suggérerais que la fréquence maximale pratique soit de 2,5 kHz. Cela donne 100 pas de résolution à partir de la fonction micros() (+- 0,025 kHz).

Si vous utilisez une broche d'entrée à cette fréquence, 3% du temps est passé dans l'interruption, ce qui signifie que le service minimum qui peut être mesuré est de 0,03. Cela équivaut à une impulsion minimale de 12uS.

Pour des fréquences plus élevées, réécrivez les ISR en fonction de votre application.

Code

  • PWMread_RCfailsafe
  • RC_Read_Example
  • RC_FrameRate
  • RC_ServoMixer_Example
PWMread_RCfailsafeArduino
Ce fichier .ino contient les fonctions et les routines d'interruption de changement de broche (ISR) utilisées pour décoder un récepteur RC et appliquer une sécurité intégrée si le signal de l'émetteur est perdu. Copiez et collez ce fichier dans le même dossier que l'esquisse principale (lorsque vous ouvrez l'esquisse, ce code apparaîtra comme un deuxième onglet dans l'IDE Arduino). Suivez ensuite les instructions du fichier./* Kelvin Nelson 24/07/2019 * * Décodage par modulation de largeur d'impulsion (PWM) du récepteur RC avec sécurité intégrée * * Ce code contient des fonctions faciles à utiliser pour mesurer les signaux d'onde carrée sur n'importe quel broches arduiuno pro mini, nano ou uno, sauf A6 et A7. * Le code est destiné à être utilisé avec les récepteurs RC, mais pourrait également être utilisé dans la plupart des autres applications de mesure PWM en remplacement direct de pulseIn (PIN, HIGH). * (à ce jour, il n'a pas été testé à une fréquence supérieure à 1 kHz ou sur un méga arduino) * * Une impulsion de signal RC peut être convertie d'une durée de largeur d'impulsion (1000-2000uS) à chaque broche d'entrée en un -+100 % (-+1,0) sortie à utiliser dans une esquisse. * L'étalonnage pour cette conversion ainsi qu'un paramètre de sécurité intégrée peuvent être définis pour chaque canal. (tolérances de sécurité intégrée 10-330Hz et 500-2500uS). * * Les données brutes pour chaque broche peuvent également être extraites, c'est-à-dire le temps d'impulsion, la largeur d'impulsion, la longueur de trame, le service et la fréquence. * * La configuration est rapide, l'organisation de ce fichier est la suivante :* * - Aperçu du code * - Liste des fonctions * - Mode d'emploi, y compris des exemples de croquis * - Variables définies par l'utilisateur -> spécifiez les broches d'entrée, l'émetteur étalonnage et sécurité intégrée. * - Variables globales et fonctions * * APERÇU DU CODE :* * Le code permet les interruptions de changement de broche sur les broches sélectionnées en définissant les registres appropriés. * * Un changement de tension sur l'une des broches sélectionnées déclenchera l'une des trois routines de service d'interruption en fonction du registre auquel la broche appartient. * - ISR(PCINT0_vect), ISR(PCINT1_vect) ou ISR(PCINT2_vect) * * Dans chaque ISR, le code détermine quelle broche a changé et note l'heure avant de revenir à la boucle principale (). * * Les intervalles de temps entre les changements de broche sont utilisés pour calculer la largeur d'impulsion et la longueur de trame. * * Les drapeaux sont définis par l'ISR pour indiquer quand de nouvelles impulsions sont reçues. * * Les Flags sont ensuite utilisés pour extraire et traiter les données collectées par chaque ISR. * * Bien qu'il ne soit pas exactement le même, ce code suit des principes similaires à ceux expliqués dans cette vidéo :https://youtu.be/bENjl1KQbvo * */// LISTE DES FONCTIONS:// TYPE DE SORTIE NOM DE LA FONCTION NOTES// void setup_pwmRead() initialise la mesure PWM en utilisant des interruptions de changement de broche// RC RECEIVER DECODING// booléen RC_avail() renvoie un HAUT lorsque de nouvelles données RC sont disponibles// float RC_decode(numéro de canal) décode le canal RC sélectionné dans la plage +-100 %, et applique une sécurité intégrée.// void print_RCpwm() Imprime les données brutes du canal RC sur le port série (utilisé pour l'étalonnage).// MESURES PWM GÉNÉRIQUES// booléen PWM_read (numéro de canal) renvoie un HAUT lorsqu'une nouvelle impulsion a été détecté sur un canal particulier. // La fonction enregistre les données d'impulsion dans des variables en dehors des routines d'interruption // et doit être appelée juste avant d'utiliser le reste des fonctions PWM. // unsigned long PWM_time() renvoie l'heure au début de l'impulsion // float PWM() renvoie la largeur d'impulsion// float PWM_period() renvoie le temps entre les impulsions// float PWM_freq() calcule la fréquence// float PWM_duty() calcule le devoir// REMARQUE :PWM_read(CH) et RC_decode(CH) utilisent les mêmes drapeaux pour détecter quand de nouvelles données sont disponibles, ce qui signifie que des données pourraient être perdues si les deux sont utilisées sur le même canal en même temps. // SUGESTION :si vous souhaitez utiliser PWM_read(CH) pour trouver la fréquence d'images d'un canal RC, appelez-le avant RC_decode(CH). La sortie de RC_decode(CH) sera alors par défaut à la sécurité intégrée.// COMMENT UTILISER, y compris des exemples de croquis// sous le titre "VARIABLES DÉFINIES PAR L'UTILISATEUR" dans le code ci-dessous://// Étape 1 :entrez les broches d'entrée dans le tableau pwmPIN[] ={}. //// - N'importe quel nombre de broches peut être entré dans pwmPIN[] (broches disponibles 0 - 13 et A0 - A5)// - Les broches n'ont pas besoin d'être dans l'ordre numérique, par exemple pwmPIN[] ={A0, 5,6,10,8} pour 5 canaux, ou pwmPIN[] ={A0,5} pour 2 canaux// - Le premier élément du tableau est le numéro de broche pour "canal 1", et le second est la broche numéro pour "canal 2"... etc.// - Toutes les broches connectées au récepteur RC doivent être au début du réseau. c'est-à-dire que les 2 premiers canaux pourraient être des entrées RC et le 3ème canal pourrait être connecté à un autre appareil comme la broche d'écho d'un capteur à ultrasons. //// Étape 2 :si un récepteur RC est connecté à toutes les entrées, réglez RC_inputs sur 0, sinon précisez le nombre de canaux connectés au récepteur c'est-à-dire RC_inputs =2; //// Etape 3 :calibrez votre émetteur en téléchargeant un simple sketch avec ce fichier .ino inclus dans le dossier sketch, et imprimez les valeurs PWM brutes en série (ou copiez et collez les fonctions nécessaires dans le croquis). // En utilisant les informations du moniteur série, mettez à jour manuellement les valeurs dans les tableaux RC_min[], RC_mid[], RC_max[] en fonction de votre émetteur (utilisez les pleins débits pour obtenir la meilleure résolution). // un exemple de croquis pour imprimer les données PWM du canal RC en série. /* void setup() { setup_pwmRead(); Serial.begin(9600); } boucle vide() { if(RC_avail()) print_RCpwm(); } */// Étape 4 :choisissez une position de sécurité intégrée pour chaque canal, comprise entre -1,0 et +1,0, et saisissez-la dans le tableau RC_failsafe[] ={}// Remarque :si vous souhaitez que l'arduino réponde à la perte du signal de l'émetteur, vous devrez peut-être désactiver la fonction de sécurité intégrée sur votre récepteur (s'il en a un). // un exemple de croquis pour vérifier le fonctionnement de la sécurité intégrée et pour imprimer les canaux calibrés en série :/* unsigned long now; // variables de synchronisation pour mettre à jour les données à intervalle régulier unsigned long rc_update; const int canaux =6 ; // spécifie le nombre de canaux de réception float RC_in[channels]; // un tableau pour stocker l'entrée calibrée du récepteur void setup() { setup_pwmRead(); Serial.begin(9600); } boucle vide() { maintenant =millis(); if(RC_avail() || now - rc_update> 25){ // si les données RC sont disponibles ou si 25 ms se sont écoulées depuis la dernière mise à jour (ajustez en fonction de la fréquence d'images du récepteur) rc_update =now; //print_RCpwm(); // décommenter pour imprimer les données brutes du récepteur vers la série pour (int i =0; i=0 &&pwmPIN[i] <=7) pwmPIN_port[i] =2; // la broche appartient à PCINT2_vect (PORT D) sinon si (pwmPIN[i]>=8 &&pwmPIN[i] <=13) pwmPIN_port[i] =0; // la broche appartient à PCINT0_vect (PORT B) // convertit le numéro de broche (c'est-à-dire la broche 11 ou la broche A0) à la position de la broche dans le registre du port. Il y a probablement une meilleure façon de le faire en utilisant une macro... // (La lecture de l'état de la broche directement à partir des registres du port accélère le code dans l'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; sinon si(pwmPIN[i] ==6) pwmPIN_reg[i] =0b01000000; sinon si(pwmPIN[i] ==7) pwmPIN_reg[i] =0b10000000; }}// SETUP OF PIN CHANGE INTERRUPTSvoid setup_pwmRead(){ for(int i =0; i num_ch) RC_inputs =num_ch; // définit le nombre de broches connectées à un récepteur RC. } // ROUTINES DE SERVICE D'INTERRUPTION (ISR) UTILISÉES POUR LIRE L'ENTRÉE PWM// le PCINT0_vect (registre du port B) réagit à tout changement sur les broches D8-13.// le PCINT1_vect (registre du port C) "" "" A0-A5. // the PCINT2_vect (D port register) "" "" D0-7.// port registers are used to speed up if statements in ISR code:// 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]; interrupts(); } 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;}

Schémas

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

Processus de fabrication

  1. C - Entrée et Sortie
  2. Animation LCD et jeux
  3. Voltmètre DIY utilisant Arduino et Smartphone
  4. Enregistreur de données de température et d'humidité
  5. Comment lire la température et l'humidité sur Blynk avec DHT11
  6. Communication Python3 et Arduino
  7. Automates cellulaires basés sur Arduino et OLED
  8. Radio FM utilisant Arduino et RDA8057M
  9. Une entrée analogique isolée pour Arduino