Efficiënte Arduino PWM Lezer & RC Ontvanger Decoder met Ingebouwde Fail-Safe
Onderdelen en benodigdheden
| Onderdeel | Aantal |
|---|---|
| Arduino UNO | 1 |
| SG90 Micro-servo motor | 2 |
Over dit project
Deze project bevat generieke, efficiënte code om een RC ontvanger (of elk PWM signaal) op elke Arduino input pin te lezen, met een fail-safe bij verlies van zendersignaal.
Video hieronder toont een Arduino Uno als servo mixer met de code PWMread_RCfailsafe.ino (beschikbaar onderaan).
- Fail-safe activeert bij geen signaal: elevator vol omhoog, aileron neutraal.
- Richting blauwe servo = gasstand.
- Bewegingsbereik (rates) blauwe servo = schuifje op zender.
- Mixing aan/uit via gear schakelaar op zender.
Inhoud
- Hoe servos worden bestuurd door PWM
- Voorbeeld toepassingen Arduino in RC modellen/robots
- Code overzicht: PWM decoderen van RC ontvanger met fail-safe
- Hoe
PWMread_RCfailsafe.inote gebruiken - Ontvanger frame rate en frequentie weergeven
- Servo mixing voorbeeld
- Rationale van de aanpak
- Beperkingen
Hoe worden servos en regelaars bestuurd door PWM?
Er wordt uitgegaan van kennis van PWM signalen voor servos/regelaars. Goede video uitleg.
Vereiste basiskennis:
- Arduino IDE
- Float, boolean, int variabelen
- If-lussen, For-lussen, Arrays
- Servo library
Voorbeeld toepassingen Arduino in RC modellen/robots
- Servo mixing, lichten schakelen, pompen/kleppen besturen, custom sequenties…
- Controller maken: vluchtstabilisatie/autopilot, heading hold, hoogte/diepte hold, auto-leveler, sense & avoid, return home…
- Reageren op signaalverlies of lage batterijspanning…
- Deze zender voor meerdere modellen/projecten zonder instellingen te wijzigen of model memory te gebruiken.
Code overzicht: PWM decoderen van RC ontvanger met fail-safe
Code meet PWM signalen met pin change interrupts. Functies automatiseren interrupt registers en data extractie van elke digitale of analoge pin (behalve A6, A7) op Uno, Nano, Pro Mini. Makkelijk te gebruiken, zelfs voor beginners.
Doel: generieke RC ontvanger met fail-safe "module" die snel tussen projecten verplaatsbaar is. Voorbeeldcode in "how to use" sectie is middelen tot een doel.
Let op: werkt niet met SoftwareSerial of andere libraries die pin change interrupts gebruiken.
Hoe de code werkt:
- Input pinnen in array (elke lengte).
- Setup functie zet pin change interrupts via registers voor elke pin in array.
- Spanningsverandering triggert een van 3 ISR's (PCINT0_vect → Port B, PCINT1_vect → Port C, PCINT2_vect → Port D).
- In ISR: FOR lus + IF statements bepalen welke pin veranderd, welk RC kanaal. Tijd genoteerd via
micros(). - Tijdsintervallen → pulsbreedte, herhalingsperiode.
- Vlaggen in ISR voor nieuwe pulsen.
- Vlaggen gebruikt door overige functies voor data extractie/verwerking.
YouTube video van Joop Brokking (eerste 8 min) legt uit hoe pin change interrupts PWM van RC ontvanger meten.
Alles wordt afgehandeld door PWMread_RCfailsafe.ino (download onderaan).
Nuttige info over port manipulatie: tronixstuff.
Naast interrupt handling: speciale functie RC_decode() converteert pulsbreedte (1000-2000µs) naar ±100% besturingssignaal. Fail-safe checkt geldig zendersignaal (toleranties 10-330Hz, 500-2500µs). Bij verlies → vooraf ingestelde fail-safe waarde.
Kalibratie waarden per zender en fail-safe posities per kanaal instelbaar in PWMread_RCfailsafe.ino.
Hoe PWMread_RCfailsafe.ino te gebruiken
Stap 1: Voorbeeld hardware setup met Arduino Uno
- Ontvanger voeden via 5V en GND.
- Signaal pinnen ontvanger → pinnen 2-7 op Arduino (vrouw-man jumpers). 2 kanaals ontvanger → alleen pinnen 2,3.
- Voor servo mixer: servo 1 signaal → pin 9, servo 2 → pin 10.

Stap 2: PWMread_RCfailsafe.ino in sketch map kopiëren
Voorbeeld sketch RC_Read_Example beschikbaar. Kopieer .ino bestand naar hooftsketch map. In IDE verschijnt tweede tabblad.

Stap 3: Input pinnen specificeren
Open hooftsketch, ga naar tab PWMread_RCfailsafe, scroll naar "USER DEFINED VARIABLES", vul array pwmPIN[] in.
Elk aantal pinnen, elke volgorde. Meer inputs = meer interrupt tijd. A6, A7 niet bruikbaar (alleen analog). Arduino MEA nog niet ondersteund.
Eerste element = kanaal 1, tweede = kanaal 2, etc. Zorg dat ontvanger kanaal 1 overeenkomt met pwmPIN[0].

Stap 4: Beschikbare functies bekijken

Stap 5: Ruwe pulsbreedte data naar serial printen
Upload RC_Read_Example, zender aan, print ruwe data. Gebruik RC_avail() om nieuwe data te checken, print_RCpwm() voor serial output.

Stap 6: Zender kalibreren
Gebruik serial data van print_RCpwm() om arrays RC_min[], RC_mid[], RC_max[] handmatig aan te passen voor kalibratie naar ±100%.

Stap 7: Gekalibreerde kanalen printen
Comment print_RCpwm() uit. Gebruik RC_decode(kanaal) voor kalibratie naar ±1. Print met decimal2percentage() + Serial.println().

Stap 8: Fail-safe instellen
Fail-safe posities in RC_failsafe[] per kanaal (±1). Zender aan/uit om te testen. RC input nu bruikbaar in sketch.
Let op: Eventuele fail-safe in ontvanger uitschakelen, anders kan Arduino niet reageren op signaalverlies.

Ontvanger frame rate en frequentie weergeven
Pulsherhalingsperiode en frequentie printen. Check nieuwe data met PWM_read(kanaal), dan PWM_period() en PWM_freq(). Voorbeeld in RC_FrameRate.ino.
Beste: kanaal 1 gebruiken (eerste puls in frame). PWM_read() gebruikt dezelfde vlaggen als RC_decode() – roep PWM_read() eerst aan.

Periode nuttig: hoeveel tijd code heeft voor volgende data. Als RC_avail() na bv. 21ms geen data ziet → RC_decode() draaien voor fail-safe of vaste frequentie (PID controller).
In RC_Read_Example.ino:
now = millis();
if(RC_avail() || now - rc_update > 21) {
rc_update = now;
// update RC input data using RC_decode()
// run a PID controller
// apply servo mixing
// position the servos
}
Servo mixing voorbeeld
RC_ServoMixer_Example.ino toont mixing van 2 kanaals (2 en 3: elevator, aileron). Ook servo richting, rates, sub-trim. Servo library op pinnen 9, 10.

Mixing: optellen/aftrekken kanalen, output limiteren -1 tot +1.
mix1 = kanaal 2 - kanaal 3 (elv - ail) mix2 = kanaal 2 + kanaal 3 (elv + ail)
Voor servo positionering: ±100% → pulsbreedte µs. Functie calc_uS() doet dit.

Standaard neutraal 1500µs, bereik ±500µs → min 1000µs (-100%), max 2000µs (+100%). Met rates, richting, sub-trim:
puls, µs = 1500 + (servo_positie_% * rates * richting + sub_trim) * 500
Richting, rates, sub-trim statisch of dynamisch via andere kanaal/invoer.
Rationale van de aanpak
pulseIn(PIN, HIGH) blokkeert loop() tijdens wachten op puls – waardevolle CPU tijd verspild. Bij meerdere inputs gaat data verloren.
Snelst: pin change interrupt + directe port manipulatie → loop() loopt met minimale vertraging. Maar complexer dan pulseIn().
Doel: beste van beide werelden. Generieke code die tussen projecten beweegt. Alleen .ino bestand kopiëren, input pinnen specificeren, functies gebruiken.
Beperkingen
De micros() functie
µs timing in 4µs stappen. 4µs precisie bij 1000-2000µs pulsen – praktisch voldoende. Verbetering naar 0.5µs mogelijk met timer interrupts (link).
Efficiëntie PWMread_RCfailsafe.ino
Bij 6-9 kanaals ontvanger: 1.4-2.0% CPU tijd in interrupt routines – acceptabel.
ISR uitvoertijd per aantal kanalen:
- 1 kanaal < 8µs
- 2 kanaals < 12µs
- 3 kanaals < 16µs
- 4 kanaals < 20µs
- 5 kanaals < 20µs
- 6 kanaals < 24µs
Meer kanalen = langere ISR (FOR lus door alle kanalen). Vernachteerbaar bij lage frequentie (50Hz) RC signalen.
~4µs ISR in/uitgang. Per puls 2x ISR (start + einde).
Tijd voor 1 puls met 6 inputs: 2 × (4 + 24) = 56µs (minimale meetbare pulsbreedte).
Alle 6 kanalen: 336µs. Bij 20ms herhalingsperiode: 1.68% interrupt load. Veel beter dan pulseIn() (blokkeert tot 20ms per pin).
Bij 2 inputs: 0.16% load.
Maximale praktische frequentie (Hz)
Voor andere doeleinden: max ~2.5kHz (100 stappen resolutie via micros()). Bij 1 input op 2.5kHz: 3% interrupt load → minimum duty 0.03 → min pulsbreedte 12µs. Hogere frequenties: ISR herschrijven voor toepassing.
Code
PWMread_RCfailsafe(hoofdlibrary)RC_Read_Example(kalibratie & fail-safe test)RC_FrameRate(frame rate/frequentie)RC_ServoMixer_Example(servo mixing demo)
Volledige code te lang voor hier – zie origineel of download van projectpagina.
Schema's
RC Ontvanger gevoed via 5V/GND van ICSP, 6 signalen → pinnen 2-7.
Micro servo 1: 5V, GND, signaal → pin 9.
Micro servo 2: 3.3V, GND, signaal → pin 10.
Productieproces
- Bouw Boeiende LCD Animaties & Games met Arduino UNO
- Een slimme voltmeter bouwen met Arduino en smartphone – Eenvoudig DIY-project
- Arduino temperatuur- en vochtigheidslogger met DHT11 en Ethernet Shield
- Temperatuur en Vochtigheid met DHT11 op Blynk - Stap-voor-Stap Arduino Tutorial
- Python 3 naar Arduino UNO: Eenvoudige Commando Besturing en LED Demo
- Bouw Real-Time Cellulaire Automaten op Arduino met 128x64 OLED Display
- Bouw een compacte FM-radio met Arduino Nano en RDA5807M
- Bouw een krachtige FM-radio ontvanger met Arduino en TEA5767 module
- Real-time RFID aanwezigheidssysteem met Arduino en Google Sheets
- Geïsoleerde analoge ingangsschakeling voor Arduino bouwen
- Invoer en uitvoer in C programmeren: Volledige gids