Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

PWM lesen, RC-Empfängereingang dekodieren und ausfallsicher anwenden

Komponenten und Verbrauchsmaterialien

Arduino UNO
× 1
SG90 Micro-Servomotor
× 2

Über dieses Projekt

Dieses Projekt enthält generischen, aber effizienten Code, der verwendet werden kann, um einfach einen RC-Empfänger (oder ein anderes PWM-Signal) an einem beliebigen Arduino-Eingangspin zu lesen und bei Verlust des Sendersignals auch eine Ausfallsicherung anzuwenden.

Unten ist ein Video, das einen Arduino uno zeigt, der als Servomischer mit dem Code PWMread_RCfailsafe.ino agiert, der unten auf dieser Seite verfügbar ist.

Hilfreicherweise kümmern sich die Funktionen in PWMread_RCfailsafe.ino um die Interrupt-Register für Sie und können leicht zwischen verschiedenen Projekten verschoben werden, die unterschiedliche Pins verwenden.

Im folgenden Videobeispiel:

  • Der Fail-Safe wird aktiviert, wenn der Empfänger kein Signal vom Sender erhält. Der Höhenruderkanal ist voll und der Querruderkanal ist auf neutral eingestellt
  • Die Richtung des blauen Servos wird durch die Gashebelposition bestimmt
  • Der Bewegungsbereich (Raten) des blauen Servos wird durch den Schieberegler an der Seite des Senders eingestellt
  • Das Mischen wird mit dem Gangschalter am Sender ein- und ausgeschaltet

Inhalt

  • Wie werden Servos durch PWM gesteuert
  • Beispielanwendungen von Arduino in RC-Modellen / Robotern
  • Codeübersicht:Decodieren Sie PWM von RC-Empfängern mit Fail-Safe
  • So verwenden Sie PWMread_RCfailsafe.ino
  • Bildrate und Frequenz des Empfängers anzeigen
  • Beispiel für eine Servomischung
  • Begründung des gewählten Ansatzes
  • Einschränkungen

Wie werden Servos und Drehzahlregler per PWM gesteuert?

Im Rest dieses Projekts wird davon ausgegangen, dass Sie die PWM-Signale verstehen, die zur Steuerung von Servos und Drehzahlreglern verwendet werden. Hier ist ein gutes Video, das erklärt, wie diese Pulsweitenmodulation (PWM)-Signale funktionieren.

Sie sollten auch über folgende Kenntnisse verfügen:

  • Die Arduino-IDE
  • Float-, Boolean- und Int-Variablen
  • Wenn Schleifen
  • For-Schleifen
  • Arrays
  • Servobibliothek

Anwendungsbeispiele von Arduino in RC-Modellen / Robotern

Sie werden nur durch Ihre Vorstellungskraft begrenzt sein:

  • Servomischung anwenden, Lichter ein-/ausschalten, Pumpen/Ventile steuern, maßgeschneiderte Sequenzen einstellen...
  • Erstellen Sie einen Controller (z. B. Flugstabilisierung/Autopilot, Kurshaltefunktion, Höhen-/Tiefenhaltefunktion, Auto-Leveler, Erkennen und Vermeiden, Heimkehren...)
  • Lassen Sie Ihr RC-Modell auf einen Signalverlust oder eine niedrige Batteriespannung reagieren...
  • Verwenden Sie denselben Sender für mehrere Modelle/Projekte, ohne Einstellungen ändern oder eine Modellspeicherfunktion verwenden zu müssen.

Codeübersicht:PWM von RC-Empfänger mit Fail-Safe decodieren

Dieser Code misst PWM-Signale (Pulsweitenmodulation) unter Verwendung von Pin-Change-Interrupts. Die verwendeten Funktionen automatisieren die Einrichtung der Interrupts und die Extraktion von Daten von jedem digitalen oder analogen Pin (außer A6 und A7) auf dem Arduino Uno, Nano oder Pro Mini. Dadurch ist der Code auch für Anfänger einfach zu verwenden.

Das Hauptziel dieses Projekts war es, einen generischen RC-Empfänger mit ausfallsicherem "Modul" zu schaffen, der schnell zwischen Projekten verschoben werden kann. Daher kann der im Abschnitt "Anwendung" gezeigte Beispielcode nur als Mittel zum Zweck verwendet werden.

Hinweis: Dieser Code funktioniert nicht mit der seriellen Software oder einer anderen Bibliothek, die Pinwechsel-Interrupts verwendet.

Für diejenigen, die daran interessiert sind, wie der Code funktioniert:

  • Die Eingangspins werden in einem Array identifiziert. Dieses Array kann eine beliebige Länge haben.
  • Eine Setup-Funktion ermöglicht Pin-Wechsel-Interrupts, indem die entsprechenden Register für jeden im Pin-Array aufgelisteten Pin gesetzt werden.
  • Eine Spannungsänderung an einem der ausgewählten Pins löst eine von drei Interrupt Service Routes (ISR) aus, abhängig davon, zu welchem ​​Portregister der Pin gehört ISR(PCINT0_vect) -> Port B, ISR(PCINT1_vect) -> Port C oder ISR(PCINT2_vect) -> Port D.
  • In jedem ISR werden eine FOR-Schleife und IF-Anweisungen verwendet, um festzustellen, welcher Pin sich geändert hat und zu welchem ​​RC-Kanal er gehört. Der Zeitpunkt des Interrupts wird über micros() notiert, bevor zur Hauptschleife() zurückgekehrt wird.
  • Die Zeitintervalle zwischen den Pin-Änderungen werden verwendet, um die Pulsbreite und die Wiederholungsperiode zu berechnen.
  • Flags werden in jedem ISR gesetzt, um anzuzeigen, wenn neue Impulse empfangen wurden
  • Die Flags werden dann von den verbleibenden Funktionen verwendet, um die von den ISRs gesammelten Daten zu extrahieren und zu verarbeiten

Das folgende YouTube-Video erstellt von Joop Brokking spricht über ein anderes Projekt, das die gleiche Methode zum Anschließen eines RC-Empfängers an Arduino verwendet. Während der ersten 8 Minuten erklärt Joopclearly, wie es geht Verwenden Sie Pinwechsel-Interrupts, um PWM-Signale von einem RC-Empfänger zu messen.

Alle diese Details werden von PWMread_RCfailsafe.ino verwaltet, das unten auf dieser Seite heruntergeladen werden kann.

Einige nützliche Informationen zur Port-Manipulation finden Sie auch hier: https://tronixstuff.com/2011/10/22/tutorial-arduino-port-manipulation/

Zusätzlich zur Behandlung von Pinwechsel-Interrupts wurde eine dedizierte Funktion RC_decode() geschrieben, um eine Pulsbreite (1000-2000uS) in ein +-100% Steuersignal von einem Sender umzuwandeln. Ein Fail-Safe prüft anhand der Signaltoleranzen von 10-330Hz und 500-2500uS auf ein gültiges Sendersignal. Wenn das Signal verloren geht, gibt RC_decode() einen vordefinierten Fail-Safe-Wert zurück.

Die Kalibrierwerte für einen bestimmten Transmitter und Fail-Safe-Positionen können für jeden Kanal in PWMread_RCfailsafe.ino . eingestellt werden

So verwenden Sie PWMread_RCfailsafe.ino

Schritt 1: Beispiel Hardware Einrichtung mit Arduino Uno

Wenn Sie dem Beispiel-Setup mit einem Arduino Uno folgen, schließen Sie Ihren Receiver wie folgt an:(andernfalls, wenn Sie Ihr eigenes Projekt verwenden, gehen Sie direkt zu Schritt 2)

  • Versorgen Sie den Empfänger mit den 5V- und GND-Pins
  • Verbinden Sie die Signalpins vom Empfänger mit den Pins 2 bis 7 des Arduino mit weiblichen zu männlichen Überbrückungsdrähten. (Wenn Sie einen 2-Kanal-Empfänger haben, schließen Sie ihn nur an die Pins 2 und 3) an.
  • Für das Beispiel eines Servomischers schließen Sie ein Servosignalkabel an Pin 9 und das andere an Pin 10 an.

Schritt 2:PWMread_RCfailsafe.ino in den Sketch-Ordner kopieren

Eine Beispielskizze RC_Read_Example steht zum Download am Ende der Seite bereit. Sie können dies als Hauptskizze verwenden, wenn Sie die folgenden Schritte ausführen.

Kopieren Sie die Datei PWMread_RCfailsafe.ino und fügen Sie sie in den Ordner ein, der Ihre Hauptskizze enthält. Wenn Sie die Skizze das nächste Mal in der IDE öffnen, wird eine zweite Registerkarte angezeigt, die den Code in PWMread_RCfailsafe.ino enthält.

Schritt 3:Angeben die Eingabe Anstecknadeln

Öffnen oder öffnen Sie die Hauptskizze in der Arduino IDE.

Klicken Sie auf die Registerkarte PWMread_RCfailsafe, scrollen Sie nach unten zum Titel "USER DEFINED VARIABLES" und geben Sie die Eingangspins in das Array pwmPIN[] ein.

Hinweis: Es können beliebig viele Pins und in beliebiger Reihenfolge verwendet werden. Beachten Sie jedoch, dass der Code umso mehr Zeit damit verbringt, die Interrupt-Routine zu adressieren, je mehr Eingaben Sie haben. Hinweis A6 und A7 sind nur analoge Pins und können nicht verwendet werden.

Der Arduino MEGA wird derzeit nicht unterstützt, dies könnte jedoch leicht behoben werden, wenn der Appetit darauf besteht.

Hinweis: das erste Element in pwmPIN[] ist Kanal 1, das zweite Element Kanal 2, etc... Wenn Sie alle Kanäle des Empfängers verwenden, ist es eine gute Idee sicherzustellen, dass der Empfängerkanal 1 dem Kanal entspricht 1 in pwmPIN[]...

Schritt 4: Rezension die verfügbar Funktionen in PWMread_RCfailsafe.ino

Schritt 5: Drucken die Puls Breite Daten zu seriell

Laden Sie den RC_Read_Example-Code hoch, schalten Sie Ihren Sender ein und drucken Sie die rohen Pulsbreitendaten seriell.

Die Funktion RC_avail() sollte verwendet werden, um zu überprüfen, ob neue Daten auf allen Kanälen empfangen wurden, und dann print_RCpwm() verwenden, um die Pulsbreitendaten seriell zu senden.

Schritt 6: Kalibrieren Sie den Sender

Verwenden der Pulsbreitendaten, die über print_RCpwm() seriell gedruckt werden, um die Werte in den Arrays RC_min[], RC_mid[] und RC_max[] manuell zu ändern, um jeden Kanal auf den Bereich von +-100% zu kalibrieren.

Schritt 7:Drucken Sie die kalibrierten Kanäle zu seriell

Kommentieren Sie die Funktion print_RCpwm() aus

Verwenden Sie die Funktion RC_decode(channel), um jeden Kanal in den Bereich +-1 zu kalibrieren.

Drucken Sie dann jeden der kalibrierten Kanäle mit der Funktion decimal2percentage() gefolgt von Serial.println("") seriell aus.

Schritt 8: Stellen Sie die Ausfallsicherheit ein

Passen Sie die Fail-Safe-Positionen im RC_failsafe[]-Array für jeden Kanal an (im Bereich +-1).

Schalten Sie den Sender ein und aus, um zu überprüfen, ob der Fail-Safe wie gewünscht funktioniert.

Der RC-Eingang kann jetzt in Ihrem Sketch verwendet werden.

Hinweis: Möglicherweise müssen Sie eine ausfallsichere Funktion im Empfänger deaktivieren, sonst kann das Arduino nicht auf den Verlust des Sendersignals reagieren.

Anzeige der Framerate und Frequenz des Empfängers

Die Impulswiederholungsperiode und -frequenz des Empfängers können seriell gedruckt werden. Überprüfen Sie mit der Funktion PWM_read(Kanalnummer), ob neue Daten auf dem ausgewählten Kanal verfügbar sind, bevor Sie PWM_period() und PWM_freq() verwenden, um die Daten zum Drucken zu extrahieren. Beispielcode ist in RC_FrameRate.ino verfügbar.

Es ist am besten, den ersten Kanal zu verwenden, da dies der erste Impuls ist, der in jedem Empfängerrahmen gesendet wird. PWM_read() verwendet dieselben Flags wie RC_decode(CH), also stellen Sie sicher, dass PWM_read() zuerst aufgerufen wird.

Siehe den Screenshot unten:

Die Empfängerperiode kann nützlich sein, da sie Ihnen sagt, wie viel Zeit der Code hat, bevor der nächste Datensatz eintrifft. Wenn RC_avail() nach einer vorbestimmten Zeit, dh 21 ms, keine neuen RC-Daten erkennt, dann führen Sie RC_decode() aus, um die Fail-Safe-Funktion auszulösen und oder um das Programm (das ein PID-Regler sein könnte) mit einer konstanten Frequenz weiterzulaufen.

Dies wird in der RC_Read_Example.ino durch die folgende if-Anweisung erreicht.

jetzt =millis();if(RC_avail() || jetzt - rc_update> 21) rc_update =jetzt; // RC-Eingangsdaten mit RC_decode() aktualisieren // PID-Regler ausführen // Servomischung anwenden // Servos positionieren} 

Beispiel für Servomischung

Ich habe RC_ServoMixer_Example.ino eingefügt, um zu zeigen, wie man zwei Empfängerkanäle mischen kann (in diesem Fall Kanal 2 und 3, Höhenruder und Querruder). Die Skizze zeigt auch eine Methode zum Einstellen von Servorichtung, Geschwindigkeit und Subtrimmung. Die Servobibliothek dient zur Ansteuerung der Servos über die Pins 9 und 10.

Unten ist ein Screenshot des Servo-Mixing-Abschnitts des Codes:

Die Mischung wird durch einfaches Addieren und Subtrahieren der beiden Kanäle und Begrenzen der Ausgabe auf den Bereich -1 bis +1 erreicht. Beim Mischen von Höhen- und Querruder erzeugen Sie zwei Ausgänge, einen für jedes Servo.

mix1 =Kanal 2 - Kanal3 (elv - ail)

mix2 =Kanal 2 + Kanal3 (elv - ail)

Vor dem Positionieren der Servos müssen Sie das +-100% (+-1) Signal in eine äquivalente Impulsbreite in Mikrosekunden für das Servo umwandeln. Im RC_ServoMixer_Example.ino verwende ich dazu eine Funktion calc_uS(). Diese Funktion befindet sich am unteren Rand der Skizze und wird im Screenshot unten gezeigt.

Die für jedes Servo angegebene Richtung, Rate und Subtrimmung wird verwendet, um eine geeignete Impulsbreite für das Servo zu berechnen.

Der Standard-Neutralimpuls beträgt 1500 uS und der normale Bereich auf beiden Seiten des Neutralleiters beträgt +-500 uS. Dies ergibt eine minimale Pulsbreite von 1000uS (-100%) und eine maximale von 2000uS (+100%). Der Puls mit angewendeten Raten, Richtung und Subtrimm kann daher wie folgt berechnet werden.

Impuls, uS =1500 + (servo_position_% * Raten * Richtung + Subtrimm) * 500

Die Servorichtung, Geschwindigkeit und Subtrimmung können statisch oder dynamisch durch die Skizze als Reaktion auf eine Eingabe von einem anderen Empfängerkanal oder auf andere Weise modifiziert werden.

Begründung des gewählten Ansatzes

Es ist möglich, einen RC-Empfänger mit der Funktion pulseIn(PIN, HIGH) zu lesen, jedoch blockt pulseIn() den Code in loop(), während dieser darauf wartet, dass ein Impuls beginnt und dann endet, wodurch wertvolle Verarbeitungszeit verschwendet wird. Bei mehr als einer Eingabe können auch Daten verloren gehen.

Aus Geschwindigkeitsgründen ist es am besten, die Pin-Change-Interrupt-Funktion des Arduino zusammen mit der direkten Port-Manipulation zu verwenden, damit der Code in loop () mit minimaler Verzögerung ausgeführt werden kann. Dies ist jedoch aufwendiger und zeitaufwändiger als das einfache Aufrufen von pulseIn(PIN, HIGH).

Daher wollte ich die Vorteile beider Welten nutzen, indem ich generischen Code schreibe, den ich zwischen Projekten verschieben kann. Alles, was Sie brauchen, ist, eine .ino-Datei (die die Funktionen und Interrupt-Routinen enthält) in den Hauptskizzenordner zu kopieren und einzufügen, die Eingangspins anzugeben und dann die Funktionen in der Skizze zu verwenden.

Einschränkungen

Die Mikros()-Funktion

Das Mikrosekunden-Timing auf dem Arduino wird mit der Funktion micros () ausgeführt. Diese Funktion zählt in 4uS-Schritten. Dies bedeutet, dass wir eine Genauigkeit von 4 Mikrosekunden haben, wenn wir die 1000-2000uS-Pulse messen. Aus praktischer Sicht ist dies mehr als ausreichend.

Falls gewünscht, ist es möglich, diese Auflösung durch Verwendung von Timer-Interrupts auf 0,5uS zu verbessern. siehe Link unten:

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

Effizienz von PWMread_RCfailsafe.ino

Wenn Sie PWMread_RCfailsafe.ino verwenden, um einen 6- oder 9-Kanal-Empfänger zu lesen, werden 1,4-2,0 % der Verarbeitungszeit damit verbracht, die Interrupt-Routinen für die Pinänderung auszuführen, was meiner Meinung nach mehr als akzeptabel ist.

Es ist jedoch immer zu gut, die Einschränkungen des Codes zu verstehen und zu wissen, wie er bei Bedarf beschleunigt werden kann.

Nachfolgend finden Sie eine Liste mit der Zeit, die für die Ausführung jedes ISR in Abhängigkeit von der Anzahl der ausgewählten Eingangskanäle benötigt wird.

1 Kanal <8uS

2 Kanäle <12uS

3 Kanäle <16uS

4 Kanäle <20uS

5 Kanäle <20uS

6 Kanäle <24uS

Hinweis: Je mehr Kanäle verwendet werden, desto länger dauert die Ausführung jedes ISR. Dies liegt daran, dass bei jedem Aufruf des ISR eine for-Schleife durch jeden Kanal läuft.

Diese zusätzliche Zeit (Ineffizienz) ist bei der Messung von niederfrequenten (z. B. 50 Hz) RC-Signalen vernachlässigbar.

Darüber hinaus dauert es ~4uS, um einen ISR zu betreten und zu verlassen. Für einen Puls läuft der ISR zweimal, einmal zu Beginn eines Pulses (LOW nach HIGH) und dann noch einmal am Ende (HIGH nach LOW).

Die Zeit zum Messen von 1 Impuls bei Verwendung von 6 RC-Eingängen beträgt

2 * (4us, um ISR einzugeben + 24uS, um ISR auszuführen) =2 * 28 =48uS.

Hinweis: Dies ist die minimal messbare Pulsbreite.

Die Zeit zum Lesen aller 6 Kanäle beträgt 288uS (6 * 48uS)

Angenommen, die Empfängerwiederholungsperiode beträgt 20 Millisekunden, dann wird der Interrupt für 1,44% (0,000288/0,02) der Zeit ausgeführt. Dies ist deutlich besser als die Verwendung der pulseIn()-Funktion. pulseIn() würde den Code für jeden Pin für bis zu 20 Millisekunden blockieren.

FYI: Wenn das Arduino nur 2 RC-Eingänge hat, läuft der ISR nur 0,16% der Zeit (0,000032/0,02)

Maximale praktische Häufigkeit (Hz)

Wenn Sie diesen Code für einen anderen Zweck verwenden, würde ich vorschlagen, dass die maximale praktische Frequenz 2,5 kHz beträgt. Dies ergibt 100 Auflösungsschritte von der micros()-Funktion (+- 0,025 kHz).

Wenn ein Eingangspin mit dieser Frequenz verwendet wird, werden 3 % der Zeit für den Interrupt verwendet, was bedeutet, dass die minimal messbare Einschaltdauer 0,03 beträgt. Dies entspricht einem minimalen Puls von 12uS.

Für höhere Frequenzen schreiben Sie den ISR entsprechend Ihrer Anwendung um.

Code

  • PWMread_RCfailsafe
  • RC_Read_Example
  • RC_FrameRate
  • RC_ServoMixer_Beispiel
PWMread_RCfailsafeArduino
Diese .ino-Datei enthält die Funktionen und Pin-Change-Interrupt-Routinen (ISR), die verwendet werden, um einen RC-Empfänger zu decodieren und eine Fail-Safe-Funktion anzuwenden, wenn das Sendersignal verloren geht. Kopieren Sie diese Datei und fügen Sie sie in denselben Ordner wie die Hauptskizze ein (wenn Sie die Skizze öffnen, wird dieser Code als zweite Registerkarte in der Arduino-IDE angezeigt). Folgen Sie dann den Anweisungen in der Datei.
/* Kelvin Nelson 24.07.2019 * * Pulsweitenmodulation (PWM)-Dekodierung von RC-Empfängern mit Failsafe * * Dieser Code enthält einfach zu bedienende Funktionen zum Messen von Rechtecksignalen auf jedem Arduino Pro Mini-, Nano- oder Uno-Pins, außer A6 und A7. * Der Code ist für die Verwendung mit RC-Empfängern vorgesehen, kann aber auch in den meisten anderen PWM-Messanwendungen als direkter Ersatz für pulseIn (PIN, HIGH) verwendet werden. * (bis heute wurde es nicht bei einer Frequenz von mehr als 1 kHz oder auf einem Arduino Mega getestet) * * Ein RC-Signalimpuls kann von einer Impulsdauer (1000-2000uS) an jedem Eingangspin in -+100 . umgewandelt werden % (-+1,0) Ausgabe zur Verwendung in einer Skizze. * Die Kalibrierung für diese Konvertierung plus eine Failsafe-Einstellung kann für jeden Kanal eingestellt werden. (Ausfallsichere Toleranzen 10-330Hz und 500-2500uS). * * Die Rohdaten für jeden Pin können ebenfalls extrahiert werden, d. h. Pulszeit, Pulsbreite, Framelänge, Tastverhältnis und Frequenz. * * Die Einrichtung ist schnell, die Organisation dieser Datei ist wie folgt:* * - Übersicht des Codes * - Liste der Funktionen * - Bedienung, einschließlich Beispielskizzen * - Benutzerdefinierte Variablen -> Eingabepins, Sender angeben Kalibrierung und ausfallsicher. * - Globale Variablen und Funktionen * * ÜBERSICHT ÜBER DEN CODE:* * Der Code aktiviert Pinwechsel-Interrupts an den ausgewählten Pins durch Setzen der entsprechenden Register. * * Eine Spannungsänderung an einem der ausgewählten Pins löst eine von drei Interrupt-Service-Routinen aus, je nachdem, zu welchem ​​Register der Pin gehört. * - ISR(PCINT0_vect), ISR(PCINT1_vect) oder ISR(PCINT2_vect) * * Innerhalb jeder ISR bestimmt der Code, welcher Pin sich geändert hat und notiert die Zeit, bevor er zur Hauptschleife() zurückkehrt. * * Die Zeitintervalle zwischen den Pin-Änderungen werden verwendet, um Pulsbreite und Framelänge zu berechnen. * * Flags werden vom ISR gesetzt, um anzuzeigen, wenn neue Impulse empfangen werden. * * Die Flags werden dann verwendet, um die von jedem ISR gesammelten Daten zu extrahieren und zu verarbeiten. * * Obwohl er nicht genau gleich ist, folgt dieser Code ähnlichen Prinzipien wie in diesem Video erklärt:https://youtu.be/bENjl1KQbvo * */// FUNKTIONSLISTE:// AUSGANGSTYP NAME DER FUNKTION NOTIZEN// void setup_pwmRead() initialisiert die PWM-Messung mit Pin-Change-Interrupts // RC RECEIVER DECODING // boolean RC_avail() gibt ein HIGH zurück, wenn neue RC-Daten verfügbar sind // float RC_decode(Kanalnummer) dekodiert den ausgewählten RC-Kanal in den Bereich +-100 % und wendet eine Failsafe-Funktion an.// void print_RCpwm() Druckt die RC-Kanal-Rohdaten an den seriellen Port (wird für die Kalibrierung verwendet).// GENERIC PWM MEASUREMENTS// Boolean PWM_read(channel number) gibt ein HIGH zurück, wenn ein neuer Impuls erzeugt wurde auf einem bestimmten Kanal erkannt. // Die Funktion speichert die Pulsdaten in Variablen außerhalb der Interrupt-Routinen // und muss kurz vor der Verwendung der restlichen PWM-Funktionen aufgerufen werden. // unsigned long PWM_time() gibt die Zeit zu Beginn des Pulses zurück // float PWM() gibt die Pulsbreite zurück // float PWM_period() gibt die Zeit zwischen den Pulsen zurück // float PWM_freq() berechnet die Frequenz // float PWM_duty() berechnet die Einschaltdauer // HINWEIS:PWM_read(CH) und RC_decode(CH) verwenden die gleichen Flags um zu erkennen, wenn neue Daten verfügbar sind, was bedeutet, dass Daten verloren gehen könnten, wenn beide gleichzeitig auf demselben Kanal verwendet werden. // VORSCHLAG:Wenn Sie PWM_read (CH) verwenden möchten, um die Bildrate eines RC-Kanals zu ermitteln, rufen Sie es auf vor RC_decode(CH). Die Ausgabe von RC_decode(CH) wird dann standardmäßig ausfallsicher sein.// VERWENDUNG, einschließlich Beispielskizzen// unter dem Titel "BENUTZERDEFINIERTE VARIABLEN" im folgenden Code://// Schritt 1:Geben Sie die Eingangspins ein in das Array pwmPIN[] ={}. //// - Eine beliebige Anzahl von Pins kann in pwmPIN[] eingegeben werden (Pins verfügbar 0 - 13 und A0 - A5)// - Die Pins müssen nicht in numerischer Reihenfolge sein, zum Beispiel pwmPIN[] ={A0, 5,6,10,8} für 5 Kanäle, oder pwmPIN[] ={A0,5} für 2 Kanäle// - Das erste Element im Array ist die Pinnummer für "Kanal 1", und das zweite ist der Pin Nummer für "Kanal 2"... etc.// - Alle mit dem RC-Empfänger verbundenen Pins müssen am Anfang des Arrays stehen. dh die ersten 2 Kanäle könnten RC-Eingänge sein und der dritte Kanal könnte mit einem anderen Gerät wie dem Echo-Pin eines Ultraschallsensors verbunden werden. //// Schritt 2:Wenn ein RC-Empfänger an alle Eingänge angeschlossen ist, setzen Sie RC_inputs auf 0, wenn nicht, geben Sie die Anzahl der an den Empfänger angeschlossenen Kanäle an, dh RC_inputs =2; //// Schritt 3:Kalibrieren Sie Ihren Sender, indem Sie eine einfache Skizze mit dieser im Skizzenordner enthaltenen .ino-Datei hochladen, und drucken Sie die rohen PWM-Werte auf seriell (alternativ kopieren Sie die benötigten Funktionen und fügen Sie sie in die Skizze ein). // Verwenden Sie die Informationen vom seriellen Monitor manuell, um die Werte in den Arrays RC_min[], RC_mid[], RC_max[] an Ihren Sender anzupassen (verwenden Sie die vollen Raten, um die beste Auflösung erhalten). // eine Beispielskizze zum Drucken der RC-Kanal-PWM-Daten seriell. /* void setup() { setup_pwmRead(); Serial.begin (9600); aufrechtzuerhalten. Void Schleife () { if (RC_avail ()) print_RCpwm (); } */// Schritt 4:Wählen Sie eine Failsafe-Position für jeden Kanal im Bereich von -1.0 bis +1.0 und geben Sie sie in das Array ein RC_failsafe[] ={}// Hinweis:Wenn Sie möchten, dass das Arduino darauf reagiert den Verlust des Sendersignals müssen Sie möglicherweise die Failsafe-Funktion Ihres Empfängers deaktivieren (sofern vorhanden). // eine Beispielskizze, um die Funktion der Failsafe-Funktion zu überprüfen und die kalibrierten Kanäle seriell auszudrucken:/* jetzt lange ohne Vorzeichen; // Timing-Variablen, um Daten in regelmäßigen Abständen zu aktualisieren unsigned long rc_update; const int Kanäle =6; // Anzahl der Empfängerkanäle angeben float RC_in[channels]; // ein Array zum Speichern der kalibrierten Eingabe vom Empfänger void setup () { setup_pwmRead (); Serial.begin (9600); aufrechtzuerhalten. Void Schleife () {jetzt =Millis (); if(RC_avail() || now - rc_update> 25){// wenn RC-Daten verfügbar sind oder seit dem letzten Update 25ms vergangen sind (an die Framerate des Empfängers anpassen) rc_update =now; //print_RCpwm(); // Entkommentieren, um Rohdaten vom Empfänger auf seriell zu drucken für (int i =0; i=0 &&pwmPIN[i] <=7) pwmPIN_port[i] =2; // Pin gehört zu PCINT2_vect (PORT D) else if (pwmPIN[i]>=8 &&pwmPIN[i] <=13) pwmPIN_port[i] =0; // Pin gehört zu PCINT0_vect (PORT B) // verdeckt die Pinnummer (d. h. Pin 11 oder Pin A0) an die Pinposition im Portregister. Es gibt wahrscheinlich einen besseren Weg, dies mit einem Makro zu tun ... // (Das direkte Lesen des Pin-Zustands aus den Port-Registern beschleunigt den Code im ISR) if(pwmPIN[i] ==0 || pwmPIN[i ] ==A0 ||pwmPIN[i] ==8) pwmPIN_reg[i] =0b00000001; sonst if(pwmPIN[i] ==1 || pwmPIN[i] ==A1 || pwmPIN[i] ==9) pwmPIN_reg[i] =0b00000010; sonst if(pwmPIN[i] ==2 || pwmPIN[i] ==A2 || pwmPIN[i] ==10) pwmPIN_reg[i] =0b00000100; sonst if(pwmPIN[i] ==3 || pwmPIN[i] ==A3 || pwmPIN[i] ==11) pwmPIN_reg[i] =0b00001000; sonst if(pwmPIN[i] ==4 || pwmPIN[i] ==A4 || pwmPIN[i] ==12) pwmPIN_reg[i] =0b00010000; sonst if(pwmPIN[i] ==5 || pwmPIN[i] ==A5 || pwmPIN[i] ==13) pwmPIN_reg[i] =0b00100000; sonst if(pwmPIN[i] ==6) pwmPIN_reg[i] =0b01000000; sonst if(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; // Definieren Sie die Anzahl der Pins, die mit einem RC-Empfänger verbunden sind. } // INTERRUPT SERVICE ROUTINES (ISR), DIE ZUM LESEN DES PWM-EINGANGS VERWENDET WERDEN // der PCINT0_vect (B-Port-Register) reagiert auf alle Änderungen an den Pins D8-13.// der PCINT1_vect (C-Port-Register) "" "" A0-A5. // das PCINT2_vect (D-Portregister) "" "" D0-7.// Portregister werden verwendet, um if-Anweisungen im ISR-Code zu beschleunigen:// 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;}

Schaltpläne

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

Herstellungsprozess

  1. C - Eingang und Ausgang
  2. LCD-Animation und -Spiele
  3. DIY-Voltmeter mit Arduino und Smartphone
  4. Temperatur- und Feuchtigkeitsdatenlogger
  5. So liest man Temperatur und Luftfeuchtigkeit auf Blynk mit DHT11
  6. Python3- und Arduino-Kommunikation
  7. Arduino- und OLED-basierte zelluläre Automaten
  8. FM-Radio mit Arduino und RDA8057M
  9. Arduino TEA5767 FM-Radioempfänger
  10. Ein isolierter Analogeingang für Arduino