Team 1

Teamname: Team 1
Teammitglieder: Michael Stenzel
  Benedikt Müller
  Alexander Blum
  Manuel Schneider

 

{autotoc addNumbering=1|addNumberingToc=true}

 

Unser Ansatz


An der Gondel des Zeppelins gibt es einen Motor, der für die Änderung der Höhe des Zeppelins
zuständig ist. Zwei weitere Motoren sind für Drehung um die eigene Achse und die Beschleunigung
nach vorne und hinten zuständig.
Zur Registrierung der Umwelt werden einige Sensoren verwendet. Die relative Höhe über dem
Untergrund soll mit einem Ultraschall Distanzsensor gemessen werden. Zudem können die Be-
schleunigungen in alle Raumrichtungen gemessen werden. Des Weiteren steht ein Drei-Achsen-
Gyroskop zur Verfügung, mit dem allerdings nur die Drehung um die z-Achse gemessen wird.
Die Lage des Zeppelins wird mittels Ultraschall ermittelt: Der Zeppelin sendet in regelmäßigen
Abständen Ultraschallimpulse, die von außen mit 3-4 Empfängern empfangen werden. Durch die
Laufzeitdifferenz wird die Lage bestimmt. Die Berechnung geschieht außerhalb mit einem zweiten
Mikrocontroller. Mittels eines XBee Moduls werden die Koordinaten zurück zum Zeppelin gesendet.

Aufgabenverteilung

  • Benedikt Müller:
    • Sensoren auslesen
    • Initialisierungsfunktion schreiben
    • Motorsteuerung
    • PC Programm
    • Kommunikationsprotokoll
  • Michael Stenzel:
    • Gondel aufbauen
    • Regelung
  • Alexander Blum:
    • XBee Module testen und richtig einstellen
    • Bodenstation
    • Kommunikationsprotokoll
  • Manuel Schneider:
    • Höhenregelung simulieren und implementieren
    • PC Programm
    • Kommunikationsprotokoll

 

Gondel

Ziel bei der Konstruktion der Gondel war es diese möglichst leicht und modular aufzubauen. Als Material wurden 6mm dicke Depron-Platten verwendet. Diese bestehen aus geschäumten Polystyrol, sind sehr leicht und deutlich stabiler als herkömmliches Styropor. Die Hauptmotoren wurden an einem 40cm langen und 3mm dicken CFK-Rohr befestigt.
Die Gondel ist so aufgebaut, dass die einzelnen Elektronikkomponenten steckbar ausgeführt sind. So lassen sich defekte Bauteile schnell austauschen und bei der Fehlersuche auch einzelne Teile testen und nicht immer nur das komplette System.
Die Teile der Gondel wurde zuvor mit eine 2D-CAD Programm gezeichnet und anschließend mit einem CNC-Laserschneider ausgeschnitten.
Nachdem die Buchsenleisten zum Aufnehmen der Elektronik in die Gondel eingeklebt waren, ging es daran alles entsprechend zu verdrahten.

Dafür wurde vorher ein Schaltplan erstellt in dem alle Komponenten und Verbindungen eingezeichnet sind. Anhand davon wurde alles mit Fädeldraht zusammengelötet. Der Fädeldraht hat den Vorteil sehr leicht zu sein, aber auch den großen Nachteil, dass er nur einen Farbe hat und sehr dünn ist und man bei vielen Kabeln schnell den Überlick verliert.

Probleme bereitet zur Zeit noch das Sensorboard. Dieses ist noch fest an der Gondel befestigt und bekommt somit alle Vibrationen der Motoren mit. Das verfälscht leider die Messwerte des Beschleunigungssensors. Außerdem ist noch unklar wie sehr der Kompass von den Motoren beeinflusst wird.

Das Sensorboard wurde jetzt auf eine 1cm dicke Schaumstoffunterlage geklebt und außerdem direkt an der Zeppelin-Hülle befestigt. So wird es von Vibrationen entkoppelt und das Barometer vor Licht und direkter Beeinflussung durch Wind geschützt.

Übersichtsplan

Der Zeppelin ist mit einem Ultraschall- und einem Infrarotsender ausgestattet. Um mit der Bodenstation zu kommunizieren besitzt er zusätzlich ein XBee-Modul. Neben der Hauptbodenstation werden 2 zusätzlichen Bodenstation zur Positionsbestimmung im Raum eingesetzt. Die Kommunikation zwischen den Bodenstationen erfolgt mittels I2C. Die Kalibrierung und die Berechnung des nächsten anzufliegenden Punktes erfolgt mittels PC. Dieser kommuniziert über USB mittels der Hauptbodenstation.

Höhenregelung

Evaluierung des Hysteresereglers

Laut Projektplan soll überprüft werden ob eine Höhenregelung mittels Hystereseregler implementierbar ist. Dazu wird zunächst ein Modell des Zeppelins entworfen. Berücksichtigt wird dabei der Auftrieb durch den senkrechten Gleichstrommotor, der Auftrieb durch die geringere Dichte von Helium als Luft, das Gewicht der Gondel und des Zeppelins sowie der Luftwiederstand. Alle relevanten Parameter werden gemessen, berechnet bzw. aus der Literatur nachgeschlagen (Dichte von Helium und Luft, Volumen und Masse und Fläche des Zeppelins, der c_w Wert des Zeppelins). Folgende Berechnungen wurden durchgeführt:

 



Das folgende File zeigt das Simulink-Modell des Zeppelins.

 


Die Modellierung des senkrechten Gleichstrommotors wurde vereinfacht. Es wird ein linearer Zusammenhang zwischen angelegter Ankerspannung und resultierender Kraftwirkung angenommen. Das Model des GM wurde dann ebenso wie das Zeppelinmodell in den Regelkreis eingefügt.

 


In den Regelkreis der Höhenregelung wurde ein Hystereseregler eingebaut. Dieser gibt abhängend von der Regelabweichung entweder 4V oder -4V aus. Die Simulierung des Hindernisses erfolgt mittels einer Störgröße im Rückführkreis. Dieses erreicht der Zeppelin nach ca. 12s und ist 0,5 Meter hoch. Die Höhe des Zeppelins h_ist und die Störgröße werden in den Matlabworkspace geladen, um dort in Diagrammen darzustellen. Es wird auf eine Führungsgröße von h_soll gleich 1 Meter geregelt.
Die Simulation erfolgt für 30 Sekunden. In jeder Millisekunde wird ein neuer Wert berechnet (fixed-step solver ode3).

In dem nachfolgenden Diagramm ist die Verlauf der Störgröße (entspricht der Kiste bzw. dem Hinderniss am Boden) in rot und die tatsächliche Höhe h_ist des Luftschiffes zu sehen.



Laut Simulation sollte also eine Regelung des Zeppelins mittels dieses Hysteresereglers möglich sein.

Im direkten Vergleich mit einem PID Regler muss sich der Hystereseregler allerdings geschlagen geben. Der PID Regler arbeitet sauberer, d.h. das Zeppelin schwingt sich nicht so schnell auf und der Regler reagiert schneller auf Abweichungen vom Sollwert. Aus diesem Grund verwenden wir bei unserem Blimp einen PID Regler für die Höhenreglung. Dieser basiert auf der selben Bibliothek wie der Richtungsregler.

Lagereglung

Richtung

Die Erfassung der Richtung des Zeppelins geschieht über den Kompass des Sensorborads, außerdem wird mit dem Gyro die Winkelgeschwindigkeit gemessen. Die Sensoren werden immer mehrere Male hintereinander ausgelesen und gemittelt um Rauschen und Sprünge rauszufiltern. Die Reglung geschieht mittels einem PID-Reglers.
Der Regler basiert auf dieser Bibliothek http://arduino.cc/playground/Code/PIDLibrary. Das Problem bei der Biblithek ist allerdings, dass man ihr nur die Regelgröße übergibt, "D" und "I" Anteil wird von der Funktion berechnet. Da wir aber den "D" Anteil mit dem Gyro messen wurde die Bibliothek so umgeschrieben, dass sie auch mit dem Sensorwert arbeitet.
Zur Zeit arbeiten wir mit einer SampleTime von 50ms, die genauen Parameter müssen wir noch durch ausprobieren herausfinden.
Mit grob eingestellten Werten arbeitet der Regler aber schon sehr gut.
PID V2 library

Software



Aktuelle Version: blimp_service_0.9.1 //Kommentiert

Sensoren

Barometer / Altimeter (MS5611-01BA)


MS5611-01BA Bibliothek mit Beispielen

Das Ansteuern und Auslesen des MS5611-01BA war mit den Beispielprogrammen aus der Bibliothek sowie 2 weiteren unabhängigen Programmen aus einem Webforum möglich.
Die im Datenblatt angegebene Genauigkeit von ~10cm war jedoch weder mit den Beispielprogrammen, den Webforen-Programmen, noch mit einem nach dem Datenblatt implementierten Algorithmus zu erreichen.
Auch konnten wir den auftretenden drift der Werte nicht genügend minimieren und haben uns daher entschieden auf diesen Sensor (vollständig) zu verzichten.
Mit dem SFR02 ist desweiteren eine wesentlich genauere Messung möglich.

Magnetometer / Kompass (HMC5883)


Da der Kompass unkalibriert, leider sehr ungenau arbeitet und die Daten im Vergleich zu reellen Richtung stark abweichen, sollte dieser zuerst kalibriert werden.
Wir sind dabei wie folgt vorgegangen. Man lässt sich mit dem Arduino die Rohwerte der X und Y-Achse ausgeben, dann zeichnet man die Werte während einer (oder zwei) kompletten Drehungen um die Z-Achse auf und plottet sie z.B. in Matlab. Im Idealfall sieht man jetzt einen Kreis um den Ursprung. Die Realität sieht anders aus, meistens hat man eine verschobene Ellipse. Um daraus einen Kreis zu bekommen, muss man die Rohwerte der Sensoren mit einem entsprechenden Offset korrigieren und entsprechend strecken oder stauchen.
Das Ganze macht man dann nochmal für die X und Z Achse und dreht dabei das Sensorboard um die Y-Achse. Jetzt sollte die Ellipse die man aus diesen Werten bekommt nurnoch in der Z Rcihtung verschoben sein. Die X-Achse kann man, da schon kalibriert, als Referenz nehmen zur Einstellung der Z-Achse nehmen.
Durch die Kalibrierung sollte der Kompass schon um einiges genauer arbeiten. Aber nur wenn er in der Ebene ist. Wird er gekippt, entstehen schnell sehr große Fehler. Die Lösung dieses Problems nennt sich Tilt-Compensation. Dazu gibts hier ein kleines Tutorial: https://www.loveelectronics.co.uk/Tutorials/13/tilt-compensated-compass-arduino-tutorial

Hier unsere Implementation des Codes aus dem Tutorial:

HeadingTiltCompensated
float HeadingTiltCompensated() {
  averageACC();
  MagnetometerScaled scaled = compass.ReadScaledAxis();

  float rollRadians = asin(average_ay);
  float pitchRadians = asin(0 - average_ax);

  //So sehen die kalibrierten Werte des Kompass aus
  float calX = scaled.XAxis + 42.5;
  float calY = (scaled.YAxis + 100.0) * 0.8;
  float calZ =(scaled.ZAxis + 10.0) * 1.05;

  // We cannot correct for tilt over 40 degrees with this algorthem, if the board is tilted as such, return 0.
  if(rollRadians > 0.78 || rollRadians < -0.78 || pitchRadians > 0.78 || pitchRadians < -0.78)
  {
    return 0;
  }

  // Some of these are used twice, so rather than computing them twice in the algorithem we precompute them before hand.
  float cosRoll = cos(rollRadians);
  float sinRoll = sin(rollRadians);  
  float cosPitch = cos(pitchRadians);
  float sinPitch = sin(pitchRadians);

  // The tilt compensation algorithem.
  float Xh = calX * cosPitch + calZ * sinPitch;
  float Yh = calX * sinRoll * sinPitch + calY * cosRoll - calZ * sinRoll * cosPitch;

  float heading = atan2(Xh, Yh);

  float declinationAngle = 0.04014; // Error for Munich
  heading += declinationAngle;

  // Correct for when signs are reversed.
  if(heading < 0)
    heading += 2*PI;

  // Check for wrap due to addition of declination.
  if(heading > 2*PI)
    heading -= 2*PI;

  return heading * 180/M_PI;
}



Und hier noch die Code und die Library zum Initialisieren des Sensors:

HMC5883LSetup
int HMC5883LSetup() {
  int error = 0;
  Serial.println("Constructing new HMC5883L");
  compass = HMC5883L(); // Construct a new HMC5883 compass.

  Serial.println("Setting scale to +/- 1.3 Ga");
  error = compass.SetScale(1.3); // Set the scale of the compass.
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));

  Serial.println("Setting measurement mode to continous.");
  error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
  return error;
}



HMC5883L Bibliothek

Gyrometer / Accelerometer (MPU6050)

MPU6050Setup
int MPU6050Setup() {
  int error = 0;
  // initialize device
  Serial.println("Initializing I2C devices...");
  accelgyro.initialize();

  // verify connection
  Serial.println("Testing device connections...");
  Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  accelgyro.testConnection() ? error=0 : error=1;
  // configure Arduino LED for
  pinMode(LED_PIN, OUTPUT);

  //set range
  //accelgyro.setFullScaleAccelRange();

  if(!accelgyro.getI2CBypassEnabled()){
    Serial.print("Enabling I2C Bypass \t");
    accelgyro.setI2CBypassEnabled(1);
    if(accelgyro.getI2CBypassEnabled()) Serial.println("Sucess");
  };

  return error;
}


MPU6050 Bibliothek

Motorsteuerung


Für die Motorsteurung gibt es zwei Funktionen. Zum einem die Funktion "setMotor" mit der man einzelne Motoren ansteuern kann. Und die Funktion "move" die alle drei Motoren ansteuert. Der Funktion übergibt man Werte für die Drehbewegung, den Schub und die Höhenänderung. Die Funktion rechnet daraus dann die Drehrichtungen und den Schub für die einzelnen Motoren aus und achtet darauf, dass keine Wertebereiche überschritten werden.

setMotor
void setMotor(char device, char direction, int duty) {

  //device = [H,R,L]
  //direction = [F, B, S, R] // Forward Backward Brake Freerun/Standby/HighImpedance
  //duty = (0-255)

  switch(device) {
  case 'R':
    PWM = 11;
    BRH = A1;
    BRL = A2;
    break;
  case 'L':
    PWM = 3;
    BRH = 12;
    BRL = 13;
    break;
  case 'H':
    PWM = 6;
    BRH = 5;
    BRL = 4;
    break;
  }
  switch(direction) {
  case 'F':
    digitalWrite(BRH, HIGH);
    digitalWrite(BRL, LOW);
    digitalWrite(7, HIGH);
    break;
  case 'B':
    digitalWrite(BRH, LOW);
    digitalWrite(BRL, HIGH);
    digitalWrite(7, HIGH);
    break;
  case 'S':
    digitalWrite(BRH, LOW);
    digitalWrite(BRL, LOW);
    digitalWrite(7, HIGH);
    break;
  case 'X':
    digitalWrite(7, LOW);
    break;
  }
  analogWrite(PWM, duty); 
}

 

move
void move(double* speed, double* rotation, double* altitude, boolean standby){
  double speedL, speedR;
  int pwr, offset = 30;

  if(standby){
    setMotor('H', 'B', 0);
    setMotor('R', 'B', 0);
    setMotor('L', 'B', 0);
    return;
  }

  if(*speed > (double)(255 - offset)){
    *speed = (double)(255 - offset);
  }
  else if(*speed < (double)(offset - 255)){
    *speed = (double)(offset - 255);
  }


  speedL = *speed + *rotation;
  speedR = *speed - *rotation;


  if(speedL > (double)(255 - offset)) {
    speedL = (double)(255 - offset);
  }

  if(speedR > (double)(255 - offset)) {
    speedR = (double)(255 - offset);
  }

  if(speedL < (double)(offset - 255)) {
    speedL = (double)(offset - 255);
  }

  if(speedR < (double)(offset - 255)) {
    speedR = (double)(offset - 255);
  }


  if(speedL < 0){
    pwr = offset + (int)(0 - speedL);
    setMotor('L', 'B', pwr);
  }
  else if(speedL > 0){
    pwr = offset + (int)speedL;
    setMotor('L', 'F', pwr);
  }
  else{
    setMotor('L', 'B', 0);
  }

  if(speedR < 0){
    pwr = offset + (int)(0 - speedR);
    setMotor('R', 'B', pwr);
  }
  else if(speedR > 0){
    pwr = offset + (int)speedR;
    setMotor('R', 'F', pwr);
  }
  else{
    setMotor('R', 'F', 0);
  }

  if(*altitude < 0){
    pwr = offset + (int)(0 - *altitude);
    setMotor('H', 'B', pwr);
  }
  else if(*altitude > 0){
    pwr = offset + (int)*altitude;
    setMotor('H', 'F', pwr);
  }
  else{
    setMotor('H', 'B', 0);
  }
}

 

Rotationsregelung Z-Achse


Die Rotationsregelung auf der Z-Achse, übernimmt ein PID-Regler den Michael, basierend auf einem PID-Regler für einen P-Eingang, mit getrennten P I D Eingangswerten und Anteilen programmiert hat. Das Magnetometer sowie das Gyrometer liefern die Werte für den proportionalen sowie den differentiellen Eingang. Der Integrale Anteil wird durch den Regler berechnet.

Eines der Probleme bei der Ausrichtung am Kompass ist der Sprung an den Grenzen des Wertebereichs [0,360]. Hier kommt es bei dem PID-Regler zu falschen Korrekturen, wenn im Bereich der Sprungstelle geregelt werden soll. Um diese Problematik zu umgehen haben wir für den PID-Regler einen Wrapper geschrieben, der dem Regler den Wertebereich [-180,+180] um die zu haltende Ausrichtung ( 0-360°) bereitstellt. Die Sprungstelle ist dadurch konstant in maximaler Entfernung zu dem geregelten Bereich.

void target_offset (double* heading, float target) {
  double error;
  error = HeadingTiltCompensated() - target;
  if (error > 180) {
    error = error - 360;
  }
  if (error < -180) {
    error = 360 + error;
  }
  *heading = error;    
}

 

Höhenregelung


Dies ist der Hystereseregler für die Höhenreglung, der allerdings einem PID-Regler weichen musste.

double hoehenregler_dreipunktregler(double* hoehe_ist){
  double u_anker;
  double e;
  e = HOEHE_SOLL - *hoehe_ist;
  if(e>0){
    if(e<HOEHE_1) u_anker = U_ANKER_MIN;
    if((e > HOEHE_1) && (e < HOEHE_2)) u_anker = U_ANKER_MITTEL;
    if(e>HOEHE_2) u_anker = U_ANKER_MAX;
  }
  if(e<0){
    if(e > -HOEHE_1) u_anker = U_ANKER_MIN;
    if((e < -HOEHE_1) && (e > -HOEHE_2)) u_anker = -U_ANKER_MITTEL;
    if(e< -HOEHE_2) u_anker = -U_ANKER_MAX;
  }
  return u_anker;
}

 

Bodenstation


Die Bodenstation stellt das Verbindungsglied zwischen dem Luftschiff und dem PC dar. Sie ist auch für die Positionsbestimmung zuständig. Die Software ist hierfür zweigeteilt und arbeitet abwechselnd die Kommunikation und die Positionsbestimmung ab.

cpp
void loop()
{
  communication();
  stateMachine();
}



Die Positionsbestimmung wurde als Final State Machine implementiert.

Zu sehen ist das Zustandsübergangsdiagramm der Bodenstation. Die "Pre"-Staus sind nur für die LED-Schaltung zuständig.

Der vollständige Programmcode ist hier zu finden: HTML mit Syntaxhighlighter und .ino Datei

Der ausführliche Programmcode zum Ansprechen der Ultraschallsensoren ist hier beschrieben: SRF02

PC-Programm

Zu Beginn muss der Rundkurs in einer Kalibrierungsphase dem Zeppelin mitgeteilt werden. Dazu wird der Zeppelin an 3 verschiedene Punkte auf dem Kreisradius bewegt, und die Koordinaten der 3 Punkte aufgenommen. Die Steuerung dieses Prozesses wird mittels eines PC-Programmes übernommen. Dieses wurden mittels der Programmiersprache Python erstellt.

Aus diesen 3 Punkten (das entspricht 6 Koordinaten) müssen nun einige Punkte berechnet werden, die der Zeppelin anfliegen soll. Dazu werden zuerst die Koordinaten des Kreismittelpunktes und der Radius des Kreises berechnet. Dazu wurde eine Gleichungssystem aufgestellt, und dieses dann entsprechen der gesuchten Variablen aufgelöst:



Mittels der Koordinaten des Kreismittelpunktes und dem Kreisradius ist der abzufliegende Kurs eindeutig bestimmt. Es kann eine Kreisgleichung aufgestellt werden und beliebig viele Punkte auf dem Kreisradius berechnet werden.

Kommunikationsprotokoll und Programmablauf


Zum Datenaustausch und zur Befehlübertragung haben wir ein Kommunikationsprotokoll entwickelt.

Ein Datenpaket besteht aus 14 Byte. Davon ist das Erste ein Startbyte (0x03) und das Letzte ein Stopbyte (0x04). Das zweite Byte (Type-Byte) enthält sowohl die Sende- und Empfängeradresse als auch eine Information über Inhalt der weiteren Bytes (Befehle oder Daten). Das dritte bis elfte Byte enthält die Daten oder Befehle. das zwölfte und 13. Byte ist eine CRC-Prüfsumme.
Ein beispielhaftes Datenpaket sieht so aus:

0x03 ASCII * ASCII X 1.Byte X-Koordinate in mm 2.Byte ASCII Y 1.Byte Y-Koordinate in mm 2.Byte ASCII Z 1.Byte Z-Koordinate in mm 2.Byte 1.Byte CRC16-Checksum 2.Byte 0x04


Das * bedeutet, dass das Paket von der Bodenstation zum PC gesendet wird und Daten enthält. Die ASCII-Zeichen X,Y,Z dienen als Trenner zwischen den Daten. Die CRC-Prüfsumme wird über die 10 vorherigen Bytes (Type und Daten) erstellt


in der LOOP:

Zeit in µsPCBodenstationBlimp
0     IR 40kHz PWM an
300     IR 40kHz PWM aus
600     IR 40kHz PWM an
900     IR 40kHz PWM aus
      delay
1.200   Empfange IR  
1.200   starte Fake-Range I2c - > SRF02 1 sende Burst I2c - > SRF02
1.250   I2c - > SRF02 2  
1.300   I2c - > SRF02 3  
       
      Sensoren auslesen, Motoren steuern etc.
       
       
70.000   lese SRF02 Messung  
71.000   Trilateration  
72.000 Empfange Positionsdaten USB Sende Positionsdaten  
  Berechne Steuerbefehle    
  Sende Steuerbefehle USB Empfange Steuerbefehle  
    Xbee Sende Steuerbefehle Xbee Empfange Steuerbefehle
       
       
100.000     SRF02 Höhe bestimmen
       
    Xbee Empfange Sensordaten Xbee Sende Sensordaten
  Empfange Sensordaten USB Sende Sensordatendaten  
       
       
200.000 Ende Ende Ende

 

 

Bodenstation:

  • Sende "Positionsbestimmung[Init]" Statuscode
  • Sende "Positionsbestimmung[Kalibrierung]" Statuscode
  • Selbstkalibrierung
  • Sende "Positionsbestimmung[Ready]" Statuscode
  • Warte auf "Positionsbestimmung[Enable]" Befehl

 

Luft:

  • Sende "Positionsbestimmung[Init]" Statuscode
    • Init SRF
    • Sende "Positionsbestimmung[Ready]" Statuscode
  • Sende "Steuersystem[Ready]" Statuscode
  • Warte auf "Positionsbestimmung[Enable]" Befehl
  • Warte auf "Steuersystem[Enable]" Befehl

 

PC:

  • Warte auf "Positionsbestimmung[Ready]"(Boden) Statuscode
  • Warte auf "Positionsbestimmung[Ready]"(Blimp) Statuscode
  • Sende "Positionsbestimmung[Enable]" Befehl
  • Ausrichtung kalibrieren: Zeppelin entlang X-Achse ausrichten und Megnetsensordaten einlesen
  • Wegpunkte festlegen
  • Sende "Steuersystem[Enable]" Befehl

 

Gerät \ BytesSTART-
Byte
TypeDataCRC
Checksum
STOP-
Byte?
1234567891011121314
USB Positionsdaten
ASCII
STX
ASCII * ASCII X X-Koordinate in mm ASCII Y Y-Koordinate in mm ASCII Z Z-Koordinate in mm CRC16-
Checksum
über Byte 2-11

IBM-CRC-16 Polynom
Startwert 0
ASCII
ETX
USB keine Positionsbestimmung ASCII * ASCII F fill with NULL
USB Steuerbefehle ASCII + ASCII H Richtung (Heading) als Differenz ASCII A Höhe (Altitude) ASCII V Geschwindigkeit
Xbee Steuerbefehle ASCII + ASCII H Richtung (Heading) als Differenz ASCII A Höhe (Altitude) ASCII V Geschwindigkeit
Xbee Sensordaten ASCII , ASCII A Höhe (Altitude) ASCII H Richtung (Heading) absolut fill with NULL
USB Sensordatendaten ASCII , ASCII A Höhe (Altitude) ASCII H Richtung (Heading) absolut fill with NULL
Command Boden
(Statuscode Query)
ASCII / ASCII Command fill with NULL
Statuscode Boden
(Comm Response)
ASCII / ASCII Statuscode fill with NULL
Command Blimp
(Statuscode Query)
ASCII - ASCII Command fill with NULL
Statuscode Blimp
(Comm Response)
ASCII - ASCII Statuscode fill with NULL

 

Statuscodes von Boden/Luft

A['0','1',E,C,B] Status Positionsbestimmung
[disbaled(ready),enabled,error,calibration,init]
S['0','1',E,B] Steuersystemstatus
[disbaled(ready),enabled,error,init]
D['0','1',E,B] Sensorstatus
[disbaled(ready),enabled,error,init]
B['0','1',E,x] Powersystem
[notEmpty,Empty,error,bin(rawvoltage)]
E ...

Command

Command[2Byte]Description
A['0','1',?] Positionsbestimmung
[disable,enable,statusquery]
S['0','1',?] Steuersystem
D['0','1',?] Sensorsystem; dis/enable sensordata transmission
B[?,x] Powersystem; [emptyStatus,rawvoltage]
C ...

Kommunikation

ZeichenUrsprung -> Ziel
* Boden -> PC
+ PC -> Luft
, Luft -> PC
/ Boden -> PC
PC -> Boden
- PC ->Luft
Luft -> PC



Das Plugin geht wohl nicht ... macht nichts, denn hier kann man sich auch alles ansehen: http://sys24.org/~ppiv/media/Programmablauf_alex.html

CRC-16-Algorithmus:

crc16
// erstelle neue Prüfsumme über 10 Bytes in char t[10]
int newcrc (char* t) {
  unsigned int crc = 0;
  for (int i = 0; i<10;i++) {
    crc = calcCRC16r(crc, *(t+i), 0xA001);
  }
  return crc;
}
// prüfe Prüfsumme über 12 Bytes, letzten beiden sind CRC16-Prüfsumme, Rückgabewert 0 wenn sie stimmt
int crc (char* t) {
  unsigned int crc = 0;
  for (int i = 0; i<12;i++) {
    crc = calcCRC16r(crc, *(t+i), 0xA001);
  }
  return crc;
}

unsigned int calcCRC16r(unsigned int crc, unsigned int c, unsigned int mask) {
  unsigned char i;
  for(i=0;i<8;i++)
  {
    if((crc ^ c) & 1) { crc=(crc>>1)^mask; }
    else crc>>=1;
    c>>=1;
  }
  return (crc);
}

 

Hardware

Bodenstation




Die Bodenstation stellt die Verbindung zwischen PC und Luftschiff her. Der PC schickt und empfängt Daten über USB, die die Bodenstation über eine Xbee-Verbindung an den Blimp weiterleiten kann. Die Bodenstation besteht aus einer Hauptstation und zwei Empfängerstationen.

eagle-Schaltplan
Per Jumper kann man zwischen i2c und UART zur Kommunikation mit den SRF02 Sensoren wählen. Das Xbee-Modul kann entwerder an der Hardware-Seriellen-Schnittstelle (UART) betrieben werden oder an einer Software- Seriellen-Schnittstelle (siehe Bit-Banging. Ebenfalls per Jumper wählbar. Jedoch is die Hardwar-Schnittstelle schon mit der USB-Verbindung belegt und in unserem Anwendungsfall nicht nutzbar.

Pinbelegung

Kabel
Farbe Funktion
braun Masse/0V
weiß 3.3V(i2c) 0V(UART)
grün SCL(i2c) Rx(Arduino)/Tx(SRF02)(UART)
gelb SDA(i2c) Tx(UART)
rosa 5V
grau IR-Empfänger

 

Arduino-Bodenstation
Pin Belegung
D0 Rx USB / Xbee
D1 Tx USB / Xbee
D2 IR-Empfänger
D3 LED rot
D4 LED gelb
D5 LED grün
D6  
D7  
D8  
D9  
D10 Rx SRF02 (UART)
D11 Tx SRF02 (UART)
D12 Rx Xbee
D13 Tx Xbee
A0  
A1  
A2  
A3  
A4 SDA (i2c)
A5 SCL (i2c)

 

Blimp

 

 

Aufbauanleitung und Inbetriebnahme

 

  • Bodenstationen im Raum verteilen und verkabeln, auf Polung achten, Farben sind markiert. Abstände der Bodenstationen messen und im Arduino-Sketch entsprechend anpassen (Hauptstation ist (x/y/z)=(0/0/0), Angabe in mm). Programm auf die Bodenstation flashen.

Beispiel:

//config starts here ---------------------------------------------
const boolean debug = true;
const boolean useI2c = true;         //srf02 mit i2c (sonst uart)
const boolean xbeeSoftSerial = true; //
const byte temperature =  21;        //temperature in Celsius
const byte receiverCount = 3;
//const byte receiverAddress[receiverCount] = {2, 3, 4}; //uart
const byte receiverAddress[receiverCount] = {114, 115, 116}; //i2c
int receiverX[receiverCount] = {0, 5790, 4507};
int receiverY[receiverCount] = {0, 0, 7053};
int receiverZ[receiverCount] = {0, 0, 0};
//config ends here ------------------------------------------------

 

 

Vorschläge zur Fortsetzung des Projekts


Bei der Umsetzung kam es zu Problemen. So war es nicht möglich im gesamten Raum eine gültige Position zu bestimmen, da meist nur eine oder zwei Bodenstationen ein Ultraschallsignal empfangen konnten. Als mögliche Lösungen für das Problem und zur eventuellen Fortsetzung schlagen wir vor:

  • eigene Ultraschallempfänger entwickeln mit mehr 'Mikrofonen' um einen größeren Empfangswinkel zu bekommen
  • mehr Bodenstationen einsetzen um eine bessere Raumabdeckung zu bekommen
  • die Ultraschallsender mit 10V statt 5V anregen um einen höheren Pegel zu bekommen

 


unser FTP-Server zum Dateiaustausch (öffentlich einsehbar): http://sys24.org/~ppiv/ Interessant sind vor allem die Verzeichnisse Eagle, code und daedalus_python


Der Projektplan und unsere Präsentationen können hier heruntergeladen werden:

Inhalt: Inhalt: Inhalt: Inhalt:
Zielsetzung Zielsetzung Gruppenaufteilung Aufgabe
Ansatz Ansatz Erreichte Meilensteine Unser Ansatz
Erfolgskriterien Erfolgskriterien Projektstatus im Zeitplan Probleme bei der Umsetzung
Aufgaben Zeitplan Abweichungen vom Projektplan Zeitplan
Zeitplan Risikoanalyse Aufgetretene Probleme Ungelöste Herausforderungen
Resourcenplan   Roadmap Lernerfolge
Risikoanalyse      


Die Libraries für die IMU haben wir von der Herstellerseite: http://www.drotek.fr/shop/en/62-imu-10dof-mpu6050-hmc5883-ms5611.html