Reaction Wheel Actuated Satellite Dynamics Test Platform

Dependencies:   mbed

Diploma Thesis in Aerospace Engineering, January 2014

University of Applied Sciences Munich, Faculty 03

Electronics:

  • 1x mbed NXP LPC 1768 Microcontroller
  • 2x XBee S1 Radios + Sparkfun USB Adapter
  • 1x CHR UM6-lt IMU
  • 4x Graupner BEC 8 Motor Controllers
  • 4x ROXXY 2826/09 Brushless Motors
  • 1x Hacker TopFuel LiPo 1300mAh Battery
  • 1x big Selfmade BreakOutBoard to connect all components
  • 1x small BreakOutBoard to connect IMU

Hardware developed with Catia V5R20

Manufactoring Technology: Rapid Prototyping - EOS Formiga P110

Controlled via text based menu with DockLight

__________________

Revision:
0:1447d2f773db
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,661 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Programm zu Lageregelung der Testplattform mit Hilfe von Reaktionskreiseln.
+// Mit UM6-LT IMU als Trägheitsplattform, XBee-Funkmodul zum seriellen Datenübertraggung und mbed
+// Mikrokontroller als Regelungs- und Stuerungscomputer.
+// Im Programm sind ein PID- und ein PD-Regler implementiert.                                       
+//
+// Datum: 10.01.2014  Autor: Grübel Dimitri
+// 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+#include "mbed.h"                                // MBED HEADER
+#include "MODSERIAL.h"                           // MBED BUFFERED SERIAL HEADER
+#include "UM6_usart.h"                           // UM6 USART HEADER
+#include "UM6_config.h"                          // UM6 CONFIG HEADER
+
+                                                 // KOMMUNIKATIONSART MIT MBED: USB/XBEE
+Serial ios(p28, p27);                            // Serielle Verbi. mit XBee über Pin: tx-28, rx-27
+//Serial ios(USBTX, USBRX);                      // Serielle Verbi. über USB Port vom PC
+
+DigitalOut rst(p11);                             // Digital Reset für the XBee, 200ns für reset
+PwmOut x_kreisel(p21);                           // Pin21-PwmOut ist für Drehung um X-Achse
+PwmOut y_kreisel(p23);                           // Pin23-PwmOut ist für Drehung um Y-Achse
+PwmOut z_kreisel(p22);                           // Pin22-PwmOut ist für Drehung um Z-Achse
+
+                                                 // HIER WIRD PWM EINGESTELLT:
+const float pulsweite = 10.0;                    // Pulsweite des Steuersignals in ms
+const float pwwork = 2.0;                        // Pulsweite des Arbeitssignals in ms
+const float startpw = 0.8;                       // Startpulsweite in ms
+const float pwmfakt = (pwwork - startpw)/200.0;  // Pulsweite pro 1% Leistung
+const float max_leistung = 75.0;                 // Leistungsbegrenzung global in %
+const float min_leistung = 10.0;                 // Notwendige Mindestleistung des Motors in %
+
+const float x_kp_min = 0.0;                      // min/max - Variablen kp für X/Y/Z-Achse
+const float x_kp_max = 3.0;
+const float y_kp_min = 0.0;
+const float y_kp_max = 3.0;
+const float z_kp_min = 0.0;
+const float z_kp_max = 3.0;
+
+const float x_kd_min = 0.0;                      // min/max - Variablen kd für X/Y/Z-Achse
+const float x_kd_max = 3.0;
+const float y_kd_min = 0.0;
+const float y_kd_max = 3.0;
+const float z_kd_min = 0.0;
+const float z_kd_max = 3.0;
+
+const float x_ki_min = 0.0;                      // min/max - Variablen ki für X/Y/Z-Achse
+const float x_ki_max = 0.5;
+const float y_ki_min = 0.0;
+const float y_ki_max = 0.5;
+const float z_ki_min = 0.0;
+const float z_ki_max = 0.5;
+
+const float x_winkel_min = -45.0;                // Winkelbegrenzung für X/Y/Z-Achse
+const float x_winkel_max =  45.0;
+const float y_winkel_min = -45.0;
+const float y_winkel_max =  45.0;
+const float z_winkel_min = -90.0;
+const float z_winkel_max =  90.0;
+
+const float regelgenauigkeit = 1.5;              // Regelgenauigkeit in Grad
+                                                 
+const float x_kp_def = 1.0;                      // DEFAULT REGELPARAMETER FÜR X/Y/Z-ACHSE
+const float x_kd_def = 0.4;
+const float x_ki_def = 0.01;
+const float y_kp_def = 1.0; 
+const float y_kd_def = 0.4;
+const float y_ki_def = 0.01;
+const float z_kp_def = 1.0; 
+const float z_kd_def = 0.4;
+const float z_ki_def = 0.01;
+
+DigitalOut uart_activity(LED1);                  // LED1 = UM6 SERIAL für Kommunikation
+       
+                                                                   
+/// FUNKTIONEN ////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// rxCallback // FUNKTION FÜR INTERRUPT - ABFRAGE DER DATEN DIE UM6-LT SENDET
+
+void rxCallback(MODSERIAL_IRQ_INFO *q) 
+{
+    if (um6_uart.rxBufferGetCount() >=  MAX_PACKET_DATA) 
+    {
+        uart_activity = !uart_activity;          // LED leuchtet wenn RxBuff hat > 40 Bytes
+        Process_um6_packet();
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// calcStellwert // FUNKTION ZUR STELLWERTBERECHNUNG FÜR MBED-PWM
+
+float calcStellwert(float leistung) 
+{                                
+    return (startpw + ((leistung + 100) * pwmfakt)) / pulsweite;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// print_gyro_data // FUNKTION ZUR AUSGABE DER AKTUELLEN WINKEL UND WINKELGESCHWINDIGKEITEN
+
+void print_gyro_data()
+{                                              
+    ios.printf("Gyro_Proc_X     %+6.1f deg/s\n", data.Gyro_Proc_X);
+    ios.printf("Gyro_Proc_Y     %+6.1f deg/s\n", data.Gyro_Proc_Y);
+    ios.printf("Gyro_Proc_Z     %+6.1f deg/s\n", data.Gyro_Proc_Z);
+    ios.printf("Roll            %+6.1f deg\n", data.Roll);
+    ios.printf("Pitch           %+6.1f deg\n", data.Pitch);
+    ios.printf("Yaw             %+6.1f deg\n\n", data.Yaw);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// print_gyro_angles // FUNKTION ZUR AUSGABE DER AKTUELLEN WINKEL
+
+void print_gyro_angles()
+{                                            
+    ios.printf("Roll            %+6.1f deg\n", data.Roll);
+    ios.printf("Pitch           %+6.1f deg\n", data.Pitch);
+    ios.printf("Yaw             %+6.1f deg\n\n", data.Yaw);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// LageregelungAchse // FUNKTION ZUR LAGEREGELUNG FÜR EINE ACHSE - STATISCH - PD Regler
+
+void LageregelungAchse(float kp, float kd, float winkel, const float& gyro_veloc, 
+                       const float& gyro_angle, PwmOut& kreisel)
+{                   
+    float start_angle = gyro_angle;
+    float winkel_soll = gyro_angle + winkel;                                                      
+    float abweichung = gyro_angle - winkel_soll;
+    float leistung_alt = 0;                           // Variablen für Bremsverfahren
+    bool start = true;
+    
+    while (fabs(abweichung) > regelgenauigkeit) 
+    {
+        float leistung = abweichung * kp - gyro_veloc * kd;
+        if (leistung > max_leistung) leistung = max_leistung;
+        if (leistung < -max_leistung) leistung = -max_leistung;
+        if (leistung > -min_leistung && leistung < -0.001) leistung = -min_leistung;
+        if (leistung < min_leistung && leistung > 0.001) leistung = min_leistung;
+         
+        int Bremsrichtung = 0;                        // Vorzeichenbestimmung der Abbremsrichtung
+         
+        if (leistung >= 0)
+            Bremsrichtung = -1;
+        else 
+            Bremsrichtung = 1;
+        
+        float Stellwert = calcStellwert(leistung);    // Berechnung Stellwert
+        kreisel.write(Stellwert);                     // Befehl an Motorregler über PWM
+        wait_ms(20);
+        abweichung = gyro_angle - winkel_soll;        // Kontrolle der Regelgenauigkeit
+        
+        if (start == true) 
+        {                                             
+            leistung_alt = leistung;
+            start = false;
+        }      
+        else 
+        {
+            if (fabs(winkel) > 5.0) 
+            {                                     
+                if ( fabs(leistung) > min_leistung) 
+                { 
+                    float delta_leistung = fabs(leistung) - fabs(leistung_alt);     // Bestimmung Abfall Delta
+                    if (delta_leistung < -0.001) 
+                    {                                 // Abbremsung des Motors bei Leistungsabnahme
+                        kreisel.write(calcStellwert(Bremsrichtung * min_leistung)); 
+                        wait_ms(10);
+                    }
+                }
+            }
+            
+            leistung_alt = leistung;
+        }                                                       // Ende des Bremsverfahrens
+        
+        if (fabs(abweichung) <= regelgenauigkeit) 
+        {             // Vorzeichen für Bremsung wird bestimmt
+            print_gyro_data();                                  // Funktionsaufruf Gyrodaten ausgeben 
+            kreisel.write(calcStellwert(Bremsrichtung * 100));  // Vollbremsung
+            wait_ms(650); 
+            kreisel.write(calcStellwert(0));                    // Motor aus
+        }
+    }
+       
+    float end_angle = gyro_angle;        
+    ios.printf("Plattform wurde gedreht um %+6.1f deg\n\n", end_angle - start_angle);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// LageregelungAchseDyn // FUNKTION ZUR LAGEREGELUNG FÜR EINE ACHSE - DYNAMISCH - PID Regler
+
+void LageregelungAchseDyn(float kp, float kd, float ki, float winkel, const float& gyro_veloc, 
+                          const float& gyro_angle, PwmOut& kreisel, float& dyn_leistung_leerlauf)
+{                   
+    
+    ios.printf("Start LageregelungAchseDyn\n");
+    float start_angle = gyro_angle;
+    float winkel_soll = gyro_angle + winkel;
+    float abweichung = gyro_angle - winkel_soll;
+    float abweichung_sum = abweichung;
+    float leistung_alt = dyn_leistung_leerlauf;
+    bool  start = true;
+    float leistung = 0.0;
+    float i_glied = 0.0;
+    
+    int cnt = 0; 
+    while (fabs(abweichung) > regelgenauigkeit) 
+    {
+        cnt += 1;
+        i_glied = abweichung_sum * 0.001 * ki;
+        ios.printf("%f\n", i_glied);
+        if (i_glied > 0.5) i_glied = 0.5;                       // I-Glied Limiter 
+        if (i_glied < -0.5) i_glied = -0.5;
+        // Sumierstelle (PID Glieder)
+        leistung = dyn_leistung_leerlauf + abweichung * kp - gyro_veloc * kd + i_glied;            
+        if (leistung > max_leistung) leistung = max_leistung;
+        if (leistung < min_leistung) leistung = min_leistung;
+        int Bremsrichtung = -1;                                 // Vorzeichen der Abbremsrichtung 
+
+        float Stellwert = calcStellwert(leistung);              // Berechnung Stellwert
+        kreisel.write(Stellwert);                               // Befehl an Motorregler über Pwm
+        wait_ms(10);       
+    
+        if (start == true) 
+        {                                   
+            leistung_alt = leistung;
+            start = false;
+        }     
+        /*else 
+        {                       
+            if (leistung > min_leistung) 
+            { 
+                float delta_leistung = leistung - leistung_alt; // Bestimmung Abfall Delta
+                
+                // bei Abnahme der Leistung - Motor abbremsen
+                if (delta_leistung < -0.0001) 
+                {                 
+                    kreisel.write(calcStellwert(Bremsrichtung * min_leistung)); 
+                    wait_ms(5);
+                }
+            }
+        }
+        */
+        leistung_alt = leistung;
+        abweichung = gyro_angle - winkel_soll;
+        abweichung_sum += abweichung;
+    }
+    
+    dyn_leistung_leerlauf = leistung - i_glied;
+    if (dyn_leistung_leerlauf < min_leistung) dyn_leistung_leerlauf = min_leistung;
+    if (dyn_leistung_leerlauf > max_leistung) dyn_leistung_leerlauf = max_leistung;
+    ios.printf("Leerlaufleistung: %f\n", dyn_leistung_leerlauf);  
+    float end_angle = gyro_angle;      
+    ios.printf("Plattform wurde gedreht um %+6.1f deg\n\n", end_angle - start_angle);
+    // Counter für durchlaufene Regelzyklen             
+    ios.printf("\nEnde LageregelungAchseDyn; Counter: %i\n\n", cnt);                               
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// main // Hauptprogramm
+
+int main() 
+{                                                          
+    ios.baud(115200);                                                // Baudrate XBee Funkmodul
+    um6_uart.baud(115200);                                           // Baudrate UM6-lt 
+    um6_uart.attach(&rxCallback, MODSERIAL::RxIrq);                  // Interrupt Funktion für UART
+
+    rst = 1;                                                         // Reset-Pin von XBee auf ON
+    
+    ios.printf("\nBitte warten, Startvorgang der Plattform...\n\n"); // Start-UP Prozedur 
+    um6_uart.putc(0xAC);                                             // Nulliert die Rate-Gyros
+    wait_ms(3500);
+    um6_uart.putc(0xAC);                                             // Nulliert die Rate-Gyros
+    wait_ms(3500);
+    um6_uart.putc(0xAC);                                             // Nulliert die Rate-Gyros
+    wait_ms(3500);
+
+    x_kreisel.period_ms(pulsweite);                                 
+    y_kreisel.period_ms(pulsweite);
+    z_kreisel.period_ms(pulsweite);
+    
+    ios.printf("\n\nTESTPLATTFORM ZUR SATELLITENLAGEREGELUNG MIT REAKTIONSKREISELN:\n\n");
+         
+    int choice1 = 0;
+    
+    do 
+    {
+        do 
+        {
+            ios.printf("\n\nBitte folgende Anweisungen ausfuehren,falls nicht bereits erfolgt!\n"
+               "Stromversorgung der Testplattform trennen und ohne Druckluft mit X-Achse auf mag."
+               " Norden ausrichten.\n"
+               "Testplattform mit Wasserwaage horizontal tarieren.\n"
+               "Danach Stromversorgung herstellen und mbed Reset-Taste betaetigen.\n\n");
+            
+            x_kreisel.write(calcStellwert(0));                       //Initialisierung X-Motorrelger 
+            y_kreisel.write(calcStellwert(0));                       //Initialisierung Y-Motorrelger
+            z_kreisel.write(calcStellwert(0));                       //Initialisierung Z-Motorrelger
+            
+            ios.printf("Menueauswahl:\n");                          
+            ios.printf("\t1 - Testplattform um einzelne Achsen drehen\n");
+            ios.printf("\t2 - Testplattform um drei Achsen drehen\n");
+            ios.printf("\t3 - Lage der Testplattform aktiv regeln fuer dynamische Fehler\n");
+            ios.printf("\t4 - Gyrodaten ausgeben [Winkel/Winkelgeschwindigkeiten]\n");
+            ios.printf("\t5 - Programm beenden\n");
+            ios.printf("\nEingabe >");
+            ios.scanf("%i", &choice1);
+        }while (choice1 < 1 || choice1 > 5);
+        
+        if (choice1 == 1)
+        { 
+            ios.printf("\nTestplattform ist initialisiert.\n\n");
+            print_gyro_angles();                                     // Funktionsaufruf Gyrodwinkel ausgeben     
+            float x_kp = x_kp_def;
+            float x_kd = x_kd_def;
+            float x_winkel = 0.0;
+            float y_kp = y_kp_def; 
+            float y_kd = y_kd_def;
+            float y_winkel = 0.0;
+            float z_kp = z_kp_def; 
+            float z_kd = z_kd_def;
+            float z_winkel = 0.0;
+
+            int choice2 = 0;
+            
+            do 
+            {
+                do 
+                {
+                    ios.printf("\n\nLAGEREGELUNG EINZELNER ACHSEN:\n\n");                         
+                    ios.printf("Menueauswahl:\n");
+                    ios.printf("\t1 - Satellitenplattform rollen (um X-Achse drehen)\n");
+                    ios.printf("\t2 - Satellitenplattform nicken (um Y-Achse drehen)\n");
+                    ios.printf("\t3 - Satellitenplattform gieren (um Z-Achse drehen)\n");
+                    ios.printf("\t4 - Auswahl abbrechen (esc).\n");
+                    ios.printf("\nEingabe >");
+                    ios.scanf("%i", &choice2); 
+                }while (choice2 < 1 || choice2 > 4);
+
+                if (choice2 == 1)
+                {
+                    ios.printf("\n Reglerparameter kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kp);          
+                    if (x_kp > x_kp_max) x_kp = x_kp_max;                 // Begrenzung X-Achse kp Pos.
+                    if (x_kp < x_kp_min) x_kp = x_kp_min;                 // Begrenzung X-Achse kp Neg.
+                    ios.printf("\n Reglerparameter kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kd); 
+                    if (x_kd > x_kd_max) x_kd = x_kd_max;                 // Begrenzung X-Achse kd Pos.
+                    if (x_kd < x_kd_min) x_kd = x_kd_min;                 // Begrenzung X-Achse kd Neg.      
+                    ios.printf("\n Rollwinkel Phi eingeben [-45 - +45] >");
+                    ios.scanf("%f", &x_winkel);
+                    if (x_winkel > x_winkel_max) x_winkel = x_winkel_max; // Begrenzung X-Achse Winkel Pos.
+                    if (x_winkel < x_winkel_min) x_winkel = x_winkel_min; // Begrenzung X-Achse Winkel Neg.   
+                    if (fabs(x_winkel) < regelgenauigkeit) ios.printf("\nRegelung ist nicht notwendig!");
+                    ios.printf("\nParameter kp = %f, Parameter kd = %f, Rollwinkel = %f\n", 
+                               x_kp, x_kd, x_winkel); 
+                    print_gyro_angles();
+                    LageregelungAchse(x_kp, x_kd, x_winkel, data.Gyro_Proc_X, data.Roll, x_kreisel);
+                }
+                else if (choice2 == 2) 
+                {
+                    ios.printf("\n Reglerparameter kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kp);
+                    if (y_kp > y_kp_max) y_kp = y_kp_max;                 // Begrenzung Y-Achse kp Pos.
+                    if (y_kp < y_kp_min) y_kp = y_kp_min;                 // Begrenzung Y-Achse kp Neg.
+                    ios.printf("\n Reglerparameter kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kd);
+                    if (y_kd > y_kd_max) y_kd = y_kd_max;                 // Begrenzung Y-Achse kd Pos.
+                    if (y_kd < y_kd_min) y_kd = y_kd_min;                 // Begrenzung Y-Achse kd Neg.
+                    ios.printf("\n Nickwinkel Theta eingeben [-45 - +45] >");
+                    ios.scanf("%f", &y_winkel);                             
+                    if (y_winkel > y_winkel_max) y_winkel = y_winkel_max; // Begrenzung Y-Achse Winkel Pos.
+                    if (y_winkel < y_winkel_min) y_winkel = y_winkel_min; // Begrenzung Y-Achse Winkel Neg.   
+                    if (fabs(y_winkel) < regelgenauigkeit) ios.printf("\nRegelung ist nicht notwendig!");
+                    ios.printf("\nParameter kp = %f, Parameter kd = %f, Nickwinkel = %f\n", 
+                                y_kp, y_kd, y_winkel); 
+                    print_gyro_angles();                                                  
+                    LageregelungAchse(y_kp, y_kd, y_winkel, data.Gyro_Proc_Y, data.Pitch, y_kreisel);
+                                     
+                 } 
+                 else if (choice2 == 3) 
+                 {                    
+                    ios.printf("\n Reglerparameter kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kp);
+                    if (z_kp > z_kp_max) z_kp = z_kp_max;                 // Begrenzung Z-Achse kp Pos.
+                    if (z_kp < z_kp_min) z_kp = z_kp_min;                 // Begrenzung Z-Achse kp Neg.
+                    ios.printf("\n Reglerparameter kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kd);
+                    if (z_kd > z_kd_max) z_kd = z_kd_max;                 // Begrenzung Z-Achse kd Pos.
+                    if (z_kd < z_kd_min) z_kd = z_kd_min;                 // Begrenzung Z-Achse kd Neg.   
+                    ios.printf("\n Gierwinkel Psi eingeben [-90 - +90] >");
+                    ios.scanf("%f", &z_winkel);      
+                    if (z_winkel > z_winkel_max) z_winkel = z_winkel_max; // Begrenzung Z-Achse Winkel Pos.
+                    if (z_winkel < z_winkel_min) z_winkel = z_winkel_min; // Begrenzung Z-Achse Winkel Neg.   
+                    if (fabs(z_winkel) < regelgenauigkeit) ios.printf("\nRegelung ist nicht notwendig!");
+                    ios.printf("\nParameter kp = %f, Parameter kd = %f, Gierwinkel = %f\n", 
+                                z_kp, z_kd, z_winkel); 
+                    print_gyro_angles();
+                    LageregelungAchse(z_kp, z_kd, z_winkel, data.Gyro_Proc_Z, data.Yaw, z_kreisel);
+                }
+            }while(choice2 != 4);
+            
+        }
+        else if (choice1 == 2)
+        {
+            float x_kp = x_kp_def;
+            float x_kd = x_kd_def;
+            float x_winkel = 0.0;
+            float y_kp = y_kp_def; 
+            float y_kd = y_kd_def;
+            float y_winkel = 0.0;
+            float z_kp = z_kp_def; 
+            float z_kd = z_kd_def;
+            float z_winkel = 0.0;
+       
+            int choice3 = 0;
+            
+            do 
+            {
+                do 
+                {
+                    ios.printf("\n\nLAGEREGELUNG ALLER ACHSEN:\n\n");
+                    ios.printf("Bitte Plattform in gewuenschte Ausgangsposition bringen.\n");
+                    ios.printf("Plattform wird in Z-Y-X Reihenfolge gedreht!\n\n");
+                    ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f\n\n", x_kp, x_kd);
+                    ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f\n\n", y_kp, y_kd);
+                    ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f\n\n", z_kp, z_kd);
+                    ios.printf("Menueauswahl:\n");
+                    ios.printf("\t1 - Regelparameter aendern?\n");
+                    ios.printf("\t2 - Plattform drehen-Winkel eingeben\n");
+                    ios.printf("\t3 - Auswahl abbrechen (esc).\n");
+                    ios.printf("\nEingabe >");
+                    ios.scanf("%i", &choice3); 
+                }while (choice3 < 1 || choice3 > 3);
+                      
+                if (choice3 == 1)
+                {
+                    ios.printf("\n Reglerparameter x_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kp);          
+                    if (x_kp > x_kp_max) x_kp = x_kp_max;                 // Begrenzung X-Achse kp Pos.
+                    if (x_kp < x_kp_min) x_kp = x_kp_min;                 // Begrenzung X-Achse kp Neg.
+                    ios.printf("\n Reglerparameter x_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kd); 
+                    if (x_kd > x_kd_max) x_kd = x_kd_max;                 // Begrenzung X-Achse kd Pos.
+                    if (x_kd < x_kd_min) x_kd = x_kd_min;                 // Begrenzung X-Achse kd Neg.
+                    ios.printf("\n Reglerparameter y_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kp);
+                    if (y_kp > y_kp_max) y_kp = y_kp_max;                 // Begrenzung Y-Achse kp Pos.
+                    if (y_kp < y_kp_min) y_kp = y_kp_min;                 // Begrenzung Y-Achse kp Neg.
+                    ios.printf("\n Reglerparameter y_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kd);
+                    if (y_kd > y_kd_max) y_kd = y_kd_max;                 // Begrenzung Y-Achse kd Pos.
+                    if (y_kd < y_kd_min) y_kd = y_kd_min;                 // Begrenzung Y-Achse kd Neg.
+                    ios.printf("\n Reglerparameter z_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kp);
+                    if (z_kp > z_kp_max) z_kp = z_kp_max;                 // Begrenzung Z-Achse kp Pos.
+                    if (z_kp < z_kp_min) z_kp = z_kp_min;                 // Begrenzung Z-Achse kp Neg.
+                    ios.printf("\n Reglerparameter z_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kd);
+                    if (z_kd > z_kd_max) z_kd = z_kd_max;                 // Begrenzung Z-Achse kd Pos.
+                    if (z_kd < z_kd_min) z_kd = z_kd_min;                 // Begrenzung Z-Achse kd Neg. 
+                    ios.printf("\n\n"); 
+                    ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f\n\n", x_kp, x_kd);
+                    ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f\n\n", y_kp, y_kd);
+                    ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f\n\n", z_kp, z_kd);
+                }
+                else if (choice3 == 2)
+                {                                                         // Eingabe der Drehwinkel
+                    ios.printf("\n Gierwinkel Psi eingeben [-90 - +90] >");
+                    ios.scanf("%f", &z_winkel);      
+                    if (z_winkel > z_winkel_max) z_winkel = z_winkel_max; // Begrenzung Z-Achse Winkel Pos.
+                    if (z_winkel < z_winkel_min) z_winkel = z_winkel_min; // Begrenzung Z-Achse Winkel Neg.
+                    ios.printf("\n Nickwinkel Theta eingeben [-45 - +45] >");
+                    ios.scanf("%f", &y_winkel);                             
+                    if (y_winkel > y_winkel_max) y_winkel = y_winkel_max; // Begrenzung Y-Achse Winkel Pos.
+                    if (y_winkel < y_winkel_min) y_winkel = y_winkel_min; // Begrenzung Y-Achse Winkel Neg.
+                    ios.printf("\n Rollwinkel Phi eingeben [-45 - +45] >");
+                    ios.scanf("%f", &x_winkel);
+                    if (x_winkel > x_winkel_max) x_winkel = x_winkel_max; // Begrenzung X-Achse Winkel Pos.
+                    if (x_winkel < x_winkel_min) x_winkel = x_winkel_min; // Begrenzung X-Achse Winkel Neg.
+                        
+                    if (fabs(z_winkel) < regelgenauigkeit && 
+                        fabs(y_winkel) < regelgenauigkeit && 
+                        fabs(x_winkel) < regelgenauigkeit)
+                    {
+                        ios.printf("\nRegelung ist nicht notwendig!");
+                    }
+                    else 
+                    {
+                        print_gyro_angles();
+                        LageregelungAchse(z_kp, z_kd, z_winkel, data.Gyro_Proc_Z, data.Yaw, z_kreisel);
+                        wait_ms(250);   
+                        LageregelungAchse(y_kp, y_kd, y_winkel, data.Gyro_Proc_Y, data.Pitch, y_kreisel);
+                        wait_ms(250);
+                        LageregelungAchse(x_kp, x_kd, x_winkel, data.Gyro_Proc_X, data.Roll, x_kreisel);
+                        print_gyro_angles();
+                        ios.printf("\n\nSoll die Plattform wieder in ihre Ausgangslage gefahren werden? "
+                                   "ja/nein\n");
+                        char yes_no[50]; 
+                        ios.scanf("%s", yes_no);
+                        
+                        if (strcmp(yes_no, "ja") == 0)    // Plattform in auf Ausgangsposition drehen
+                        {                       
+                            LageregelungAchse(x_kp, x_kd, -x_winkel, data.Gyro_Proc_X, data.Roll, x_kreisel);
+                            wait_ms(250);  
+                            LageregelungAchse(y_kp, y_kd, -y_winkel, data.Gyro_Proc_Y, data.Pitch, y_kreisel);
+                            wait_ms(250);
+                            LageregelungAchse(z_kp, z_kd, -z_winkel, data.Gyro_Proc_Z, data.Yaw, z_kreisel);
+                            print_gyro_angles();
+                        }
+                    }
+                }  
+                            
+            }while(choice3 != 3);
+        }
+        else if (choice1 == 3)
+        {
+            float x_kp = x_kp_def;
+            float x_kd = x_kd_def;
+            float x_ki = x_ki_def;
+            float y_kp = y_kp_def; 
+            float y_kd = y_kd_def;
+            float y_ki = y_ki_def;
+            float z_kp = z_kp_def; 
+            float z_kd = z_kd_def;
+            float z_ki = z_ki_def;
+       
+            int choice4 = 0;
+            
+            do 
+            {
+                do 
+                {
+                    ios.printf("\n\nLage der Testplattform aktiv regeln fuer dynamische Fehler"
+                               " (Position halten):\n\n");
+                    ios.printf("\n\nBitte Plattform in gewuenschte Ausgangsposition bringen und halten "
+                               "bis die Kreisel "
+                               "ihre Leerlaufdrehzahl erreicht haben.\n\n");
+                    ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f ki = %f\n", 
+                                x_kp, x_kd, x_ki); 
+                    ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f ki = %f\n", 
+                                y_kp, y_kd, y_ki);
+                    ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f ki = %f\n\n", 
+                                z_kp, z_kd, z_ki);
+                    ios.printf("Menueauswahl:\n");
+                    ios.printf("\t1 - Regelparameter aendern?\n");
+                    ios.printf("\t2 - Plattform aktivieren\n");
+                    ios.printf("\t3 - Auswahl abbrechen (esc).\n");
+                    ios.printf("\nEingabe >");
+                    ios.scanf("%i", &choice4); 
+                }while (choice4 < 1 || choice4 > 3);  
+                       
+                if (choice4 == 1)
+                {
+                    /*
+                    ios.printf("\n Reglerparameter x_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kp);          
+                    if (x_kp > x_kp_max) x_kp = x_kp_max;                 // Begrenzung X-Achse kp Pos.
+                    if (x_kp < x_kp_min) x_kp = x_kp_min;                 // Begrenzung X-Achse kp Neg.
+                    ios.printf("\n Reglerparameter x_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kd); 
+                    if (x_kd > x_kd_max) x_kd = x_kd_max;                 // Begrenzung X-Achse kd Pos.
+                    if (x_kd < x_kd_min) x_kd = x_kd_min;                 // Begrenzung X-Achse kd Neg.
+                    ios.printf("\n Reglerparameter x_ki eingeben [0 - +0.5] >");
+                    ios.scanf("%f", &x_ki); 
+                    if (x_ki > x_ki_max) x_ki = x_ki_max;                 // Begrenzung X-Achse ki Pos.
+                    if (x_ki < x_ki_min) x_ki = x_ki_min;                 // Begrenzung X-Achse ki Neg.
+                    ios.printf("\n Reglerparameter y_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kp);
+                    if (y_kp > y_kp_max) y_kp = y_kp_max;                 // Begrenzung Y-Achse kp Pos.
+                    if (y_kp < y_kp_min) y_kp = y_kp_min;                 // Begrenzung Y-Achse kp Neg.
+                    ios.printf("\n Reglerparameter y_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kd);
+                    if (y_kd > y_kd_max) y_kd = y_kd_max;                 // Begrenzung Y-Achse kd Pos.
+                    if (y_kd < y_kd_min) y_kd = y_kd_min;                 // Begrenzung Y-Achse kd Neg.
+                    ios.printf("\n Reglerparameter y_ki eingeben [0 - +0.5] >");
+                    ios.scanf("%f", &y_ki); 
+                    if (y_ki > y_ki_max) y_ki = y_ki_max;                 // Begrenzung Y-Achse ki Pos.
+                    if (y_ki < y_ki_min) y_ki = y_ki_min;                 // Begrenzung Y-Achse ki Neg.
+                    */  
+                    ios.printf("\n Reglerparameter z_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kp);
+                    if (z_kp > z_kp_max) z_kp = z_kp_max;                 // Begrenzung Z-Achse kp Pos.
+                    if (z_kp < z_kp_min) z_kp = z_kp_min;                 // Begrenzung Z-Achse kp Neg.
+                    ios.printf("\n Reglerparameter z_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kd);
+                    if (z_kd > z_kd_max) z_kd = z_kd_max;                 // Begrenzung Z-Achse kd Pos.
+                    if (z_kd < z_kd_min) z_kd = z_kd_min;                 // Begrenzung Z-Achse kd Neg. 
+                    ios.printf("\n Reglerparameter z_ki eingeben [0 - +0.5] >");
+                    ios.scanf("%f", &z_ki); 
+                    if (z_ki > z_ki_max) z_ki = z_ki_max;                 // Begrenzung Z-Achse ki Pos.
+                    if (z_ki < z_ki_min) z_ki = z_ki_min;                 // Begrenzung Z-Achse ki Neg.
+                    ios.printf("\n\n"); 
+                    //ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f ki = %f\n\n", 
+                    //            x_kp, x_kd, x_ki); 
+                    //ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f ki = %f\n\n", 
+                    //            y_kp, y_kd, y_ki);
+                    ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f ki = %f\n\n", 
+                                z_kp, z_kd, z_ki);
+                }
+                else if (choice4 == 2)
+                {                                       
+                    ios.printf("\n\nUm abzubrechen bitte Reset-Taste an mbed betaetigen!\n\n");
+                    float ziel_x_winkel = data.Roll;
+                    float ziel_y_winkel = data.Pitch;
+                    float ziel_z_winkel = data.Yaw;
+                    
+                    print_gyro_angles();                                 
+                    float x_dyn_leistung_leerlauf = (min_leistung + max_leistung)/2; // Leistung im Leerlauf 
+                    float y_dyn_leistung_leerlauf = (min_leistung + max_leistung)/2; // Leistung im Leerlauf 
+                    float z_dyn_leistung_leerlauf = (min_leistung + max_leistung)/2; // Leistung im Leerlauf
+                    
+                    wait_ms(2000);
+                    z_kreisel.write(calcStellwert(z_dyn_leistung_leerlauf));
+                    //y_kreisel.write(calcStellwert(y_dyn_leistung_leerlauf));
+                    //x_kreisel.write(calcStellwert(x_dyn_leistung_leerlauf));
+            
+                    while(1)
+                    {
+                        while (fabs(ziel_z_winkel - data.Yaw) > regelgenauigkeit)
+                        {     
+                            LageregelungAchseDyn(z_kp, z_kd, z_ki, ziel_z_winkel - data.Yaw, data.Gyro_Proc_Z, 
+                                                 data.Yaw, z_kreisel, z_dyn_leistung_leerlauf);
+                        }
+                        
+                        /*
+                        while (fabs(ziel_y_winkel - data.Pitch) > regelgenauigkeit)
+                        {  
+                            LageregelungAchseDyn(y_kp, y_kd, y_ki, ziel_y_winkel - data.Roll, data.Gyro_Proc_Y, 
+                                                 data.Pitch, y_kreisel, y_dyn_leistung_leerlauf);  
+                        }
+                        
+                        while (fabs(ziel_x_winkel - data.Roll) > regelgenauigkeit)
+                        {
+                            LageregelungAchseDyn(x_kp, x_kd, x_ki, ziel_x_winkel - data.Pitch, data.Gyro_Proc_X, 
+                                                 data.Roll, x_kreisel, x_dyn_leistung_leerlauf);
+                        }
+                        */
+                    }
+                }
+            }while(choice4 != 3);
+        }
+        else if (choice1 == 4)
+        { 
+            print_gyro_data();
+        }
+          
+    }while(choice1 != 5); 
+ 
+    ios.printf("\n\nProgramm beendet.\n");
+}
\ No newline at end of file