Modellfluginfo
Informationen, Tipps für Anfänger, günstige Angebote und Berichte zum Thema Modellflug

5.8 GHz 4-fach Diversity Empfänger

Prototyp des Diversity Empfängers
Prototyp des Diversity Empfängers

Mit wenigen Bauteilen lässt sich ein RSSI-basierter 4-fach  Diversityempfänger recht einfach selber bauen und für FPV einsetzen. Ohne Diversity zu fliegen ist mit 5.8 GHz nur mit einem Antennentracking-System sicher möglich. Diese Trackingsysteme sind allerdings relativ teuer und aufwändig in der Handhabung. Darüberhinaus sind Trackingsysteme aufgrund der Mechanik fehleranfälliger als Diversitysysteme. 4 Biloop-Antennen über ein Diversitymodul geschaltet sind für Flüge bis 500 Meter auch ohne Antennenachführung völlig ausreichend.

Ein 2-fach 5.8 GHz Diversityempfänger kostet schon über 200 EUR. Nimmt man die günstigen Airwave 682RX Module, so kann man diese zu einem 4-Fach Diversity zusammenschalten. Über das RSSI Signal der Airwave AVM682RX Module kann man über einen Arduino Pro Mini einfach den Empfänger mit dem besten Signal durchschalten. Als Videoswitch kann der Philips CD4052 eingesetzt werden, den es bei ELV für 0,31 EUR zu kaufen gibt. Zwei davon reichen, um das Videosignal und zwei Audiosignale zu schalten.

Für die gesamte Steuerung reicht ein Arduino Pro Mini. Über 4 Analoge Eingänge werden die RSSI Signale ausgewertet. Die 4052 Video Switches werden über zwei Bit angesteuert und zusätzlich lassen sich die Kanäle der Airwave Empfänger beim Einschalten automatisch einstellen. 

Über ein 4 zeiliges LCD Display, das sich über den Arduino sehr einfach ansteuern lässt können die Signalstärke und der aktuelle Kanal angezeigt werden. Damit lassen sich dann auch einzelne selbstgebaute FPV-Antennen testen und vergleichen.

Ein solcher Empfänger kostet zwar etwas Zeit zum Löten und in das Gehäuse einbauen. Mit unter 200 EUR kosten ist er aber deutlich günstiger als eine Kauflösung und bietet außerdem durch die Programmierung einiges an Optimierungsmöglichkeiten, wie z.B. Schalthysterese, für die jeweilige FPV Anwendung. 

Zwischensender für kabelloses FPV

Richtig komfortabel wird es dann, wenn im Empfänger gleichzeitig noch ein Sender untergebracht wird, der auf einem zweiten Kanal zur Videobrille sendet. Eine Fatshark mit eingebautem Empfänger kann dann auch für ausgedehnte Flüge genutzt werden, was mit der Standard Stabantenne nicht möglich ist. Der Empfänger dient dann praktisch als Zwischenstation oder Verstärker. Wichtig ist dann nur, dass man sich als Pilot in der Nähe des Empfängers aufhält. Da der Aufbau recht kompakt ist, und keine mechanische Antennennachführung stattfindet, kann der Empfänger auch z.B. unter dem RC-Senderpult befestigt werden.

Schema des FPV Empfängers mit 4 BiLoop Antennen und Zwischensender
Schema des FPV Empfängers mit 4 BiLoop Antennen und Zwischensender

Schaltplan des Empfängers

Da ich zu den Intuitivlöter gehöre, habe ich leider keinen Schaltplan. Dieser ist auch kaum notwendig, denn sowohl die Beschaltung der Airwave-Module als auch die der 4052er Multiplexer sind in deren Datenblätter gut beschrieben.

Quelltext zur Programmierung des Arduino Pro Mini

// Multi Diversity FPV Receiver - Version 0.9.3
//
// Visit <http://modellfluginfo.de/Modellflugzeug/Blog/fpv-diversity-empfaenger.php for detailed instructions
//
// Copyright (c) by Achim Bartelt <http://modellfluginfo.de>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// Changlog
//
// 0.9.0 (28. May 2011)
//
// 0.9.1 (2. June 2011)
//       Changed datatypes to long
// 0.9.2 (30. Dec 2011)
//       Sending statistics to serial monitor

#include <LiquidCrystal.h>

byte symbol = 255;
 
int rssi1 = A0;
int rssi2 = A1;
int rssi3 = A2;
int rssi4 = A3;

int tmpRssiValue = 0;

int rssiValue1 = 0;
int rssiValue2 = 0;
int rssiValue3 = 0;
int rssiValue4 = 0;  

int hasFoundChanel1 = 0;
int hasFoundChanel2 = 0;
int hasFoundChanel3 = 0;
int hasFoundChanel4 = 0;

unsigned long timeSelectedChanel1 = 0;
unsigned long timeSelectedChanel2 = 0;
unsigned long timeSelectedChanel3 = 0;
unsigned long timeSelectedChanel4 = 0;

unsigned long timeSelectedSum = 1;

int tmpPerc = 0;

unsigned int percSelectedChanel1 = 0;
unsigned int percSelectedChanel2 = 0;
unsigned int percSelectedChanel3 = 0;
unsigned int percSelectedChanel4 = 0;

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

void setup() {
  
  lcd.begin(16, 2);
  
  pinMode(8, OUTPUT);     
  pinMode(9, OUTPUT); 
  pinMode(10, OUTPUT); 
  pinMode(11, OUTPUT); 
  pinMode(12, OUTPUT); 
  pinMode(13, OUTPUT); 
  
  digitalWrite(10, HIGH);
  digitalWrite(11, HIGH); 
  digitalWrite(12, HIGH);
  digitalWrite(13, HIGH);   

  Serial.begin(9600);  
  
}

void loop(){  
  
  // Map values to defined range
  rssiValue1 = map(constrain(analogRead(rssi1), 100, 480), 100, 480, 99, 0);
  rssiValue2 = map(constrain(analogRead(rssi2), 100, 480), 100, 480, 99, 0);
  rssiValue3 = map(constrain(analogRead(rssi3), 100, 480), 100, 480, 99, 0); 
  rssiValue4 = map(constrain(analogRead(rssi4), 100, 480), 100, 480, 99, 0); 
  
  //Info to searial port  
  Serial.print(rssiValue1); 
  Serial.print(";");  
  Serial.print(rssiValue2);
  Serial.print(";");    
  Serial.print(rssiValue3);  
  Serial.print(";");    
  Serial.print(rssiValue4);    
  Serial.print(";");    
  Serial.print(timeSelectedSum); 
  Serial.print(";");    
  Serial.print(timeSelectedChanel1);   
  Serial.print(";");    
  Serial.print(timeSelectedChanel2); 
  Serial.print(";");    
  Serial.print(timeSelectedChanel3); 
  Serial.print(";");    
  Serial.print(timeSelectedChanel4);  
  Serial.print(";");  
  Serial.print(percSelectedChanel1); 
  Serial.print(";");  
  Serial.print(percSelectedChanel2); 
  Serial.print(";");  
  Serial.print(percSelectedChanel3); 
  Serial.print(";");  
  Serial.print(percSelectedChanel4); 
  Serial.print(";");
  Serial.print("\n");   
  
  //Display rssi values
  if(tmpRssiValue == 2){
    lcd.setCursor(0, 0);
    lcd.print("                ");    
    lcd.setCursor(0, 0);
    lcd.print(rssiValue1);
    lcd.setCursor(4, 0);
    lcd.print(rssiValue2);
    lcd.setCursor(8, 0);
    lcd.print(rssiValue3);
    lcd.setCursor(12, 0);
    lcd.print(rssiValue4);
    tmpRssiValue = 0;
  } 
  tmpRssiValue++;
  
  lcd.setCursor(0, 1);   
  
  //Select channels
  if(hasFoundChanel1 == 0 && rssiValue1 < 80){
    digitalWrite(13, LOW);
    digitalWrite(13, HIGH);
    lcd.setCursor(0, 1);
    lcd.print("C");
    delay(200);    
    lcd.setCursor(0, 1);    
    lcd.print(" ");    
  }
  else if(hasFoundChanel1 == 1){
    lcd.setCursor(2, 0);
    lcd.print(".");  
  }    
  else if(rssiValue1 >= 90){
    hasFoundChanel1 = 1;
  }
  
  if(hasFoundChanel2 == 0 && rssiValue2 < 80){
    digitalWrite(12, LOW);
    digitalWrite(12, HIGH); 
    lcd.setCursor(4, 1);
    lcd.print("C");
    delay(200);    
    lcd.setCursor(4, 1);    
    lcd.print(" ");    
  } 
  else if(hasFoundChanel2 == 1){
    lcd.setCursor(6, 0);
    lcd.print(".");  
  }  
  else if(rssiValue2 >= 90){
    hasFoundChanel2 = 1;
  }
  
  if(hasFoundChanel3 == 0 && rssiValue3 < 80){
    digitalWrite(11, LOW);
    digitalWrite(11, HIGH);  
    lcd.setCursor(8, 1);
    lcd.print("C");
    delay(200);    
    lcd.setCursor(8, 1);    
    lcd.print(" ");    
  }
  else if(hasFoundChanel3 == 1){
    lcd.setCursor(10, 0);
    lcd.print(".");  
  }    
  else if(rssiValue3 >= 90){
    hasFoundChanel3 = 1;   
  }
  
  if(hasFoundChanel4 == 0 && rssiValue4 < 80){
    digitalWrite(10, LOW);
    digitalWrite(10, HIGH);      
    lcd.setCursor(12, 1);
    lcd.print("C");
    delay(200);    
    lcd.setCursor(12, 1);    
    lcd.print(" ");
  }
  else if(hasFoundChanel4 == 1){
    lcd.setCursor(14, 0);
    lcd.print(".");  
  }    
  else if(rssiValue4 >= 90){
    hasFoundChanel4 = 1;  
  }  
  
  //Select receiver with best rssi value and display selected channel
  if(rssiValue1 > rssiValue2 && rssiValue1 > rssiValue3 && rssiValue1 > rssiValue4){
    digitalWrite(8, LOW);
    digitalWrite(9, LOW); 
    
    timeSelectedChanel1++;    

    lcd.setCursor(2, 1);
    lcd.print(symbol);    
    lcd.setCursor(6, 1);
    lcd.print(" ");  
    lcd.setCursor(10, 1);
    lcd.print(" ");  
    lcd.setCursor(14, 1);
    lcd.print(" ");      
  }  
  else if(rssiValue2 > rssiValue1 && rssiValue2 > rssiValue3 && rssiValue2 > rssiValue4){
    digitalWrite(8, HIGH);
    digitalWrite(9, LOW); 
    
    timeSelectedChanel2++;
    
    lcd.setCursor(2, 1);
    lcd.print(" ");    
    lcd.setCursor(6, 1);
    lcd.print(symbol); 
    lcd.setCursor(10, 1);
    lcd.print(" ");  
    lcd.setCursor(14, 1);
    lcd.print(" ");        
  }
  else if(rssiValue3 > rssiValue1 && rssiValue3 > rssiValue2 && rssiValue3 > rssiValue4){
    digitalWrite(8, LOW);
    digitalWrite(9, HIGH);
    
    timeSelectedChanel3++;            
    
    lcd.setCursor(2, 1);
    lcd.print(" ");    
    lcd.setCursor(6, 1);
    lcd.print(" ");  
    lcd.setCursor(10, 1);
    lcd.print(symbol); 
    lcd.setCursor(14, 1);
    lcd.print(" ");          
  }  
  else if(rssiValue4 > rssiValue1 && rssiValue4 > rssiValue2 && rssiValue4 > rssiValue3){
    digitalWrite(8, HIGH);
    digitalWrite(9, HIGH);
   
    timeSelectedChanel4++; 
    
    lcd.setCursor(2, 1);
    lcd.print(" ");    
    lcd.setCursor(6, 1);
    lcd.print(" ");  
    lcd.setCursor(10, 1);
    lcd.print(" ");  
    lcd.setCursor(14, 1);
    lcd.print(symbol);        
  }   
  
  timeSelectedSum = timeSelectedChanel1 + timeSelectedChanel2 + timeSelectedChanel3 + timeSelectedChanel4;
  
  // Display percentage of selected time
  if(tmpPerc == 8){
    lcd.setCursor(0, 1);
    lcd.print("                ");     
    percSelectedChanel1 = timeSelectedChanel1 * 100 / timeSelectedSum;
    lcd.setCursor(0, 1);    
    lcd.print(percSelectedChanel1);    
            
    percSelectedChanel2 = timeSelectedChanel2 * 100 / timeSelectedSum;
    lcd.setCursor(4, 1);    
    lcd.print(percSelectedChanel2);     
    
    percSelectedChanel3 = timeSelectedChanel3 * 100 / timeSelectedSum;
    lcd.setCursor(8, 1);    
    lcd.print(percSelectedChanel3);       

    percSelectedChanel4 = timeSelectedChanel4 * 100 / timeSelectedSum; 
    lcd.setCursor(12, 1);    
    lcd.print(percSelectedChanel4); 
    tmpPerc = 0;  
  }
  tmpPerc++;
  
  delay(100);    
}

Bezugsquellen der Bauteile für den Diversityempfänger