Serielle Signale in versch. Variablen speichern

Hi alle zusammen,
in naher zukunft hab ich mir folgendes Vorgenommen:
Ich möchte mit 2 X-Bees und 2 Arduino-Boards Live-Daten aus einem Flugmodell zum Boden übertragen, und dort auf einem Display ausgeben. Das Board im Modell liest verschiedene Sensoren aus, speichert es in verschiedene Variablen und schickt diese dann als String per X-Bee zum Boden. Das Board am Boden soll diese Daten dann wieder aufbereiten, und ich versch. Variablen speichern, sodass ich die weiterverarbeiten kann.
Nur genau da hängt es, wie teile ich das Lange Signal aus dem Flugzeug in die kurzen Signale auf?
Das kommt z.B. aus dem Flugzeug:

"T=34,V=122,H=82,S=56"

Soll Später dann mal als folgendes interpretiert werden:

Temperatur: 34°C
Spannung: 12.2V
Höhe: 82m
Geschwindigkeit: 56km/h

Wie bekomme ich es jetzt hin dass der "Bodenarduino" die Werte in die Variablen T, V, H und S speichert?
Nach langem suchen habe ich nichts gefunden, was mir wirklich weiterhilft.
Ich habe jetzt einen kleinen "Testcode" geschrieben, der 2 Werte nacheinander speichert, die anschließend am Serial Monitor ausgegeben werden. Das funktioniert leider nicht ganz so wie ich mir das vorgestellt habe. Ich hoffe ich habe keinen totalen mist gebaut, hier einfach mal der Code:

int hoehe;
int geschwindigkeit;

void setup() {
  Serial.begin(9600);
}
void loop() {

  height();          //Gehe zu "height"
  speed();           //Gehe zu "speed"
  ausgabe();        //Gehe zu "ausgabe"
}

void height() {
  if (Serial.available() ) {       //wenn Serielle Daten verfügbar sind...
    hoehe = Serial.read();         //die Empfangenen Daten in hoehe speichern
  }
  else {                           //ansonsten "height" wiederholen
    height();
  }
}

void speed() {                    
  if (Serial.available() ) {            //wenn Serielle Daten Verfügbar sind...
    geschwindigkeit = Serial.read();    //die Empfangenen Daten in gescheindigkeit speichern
  }
  else {                                //ansonsten "speed" wiederholen
    speed();
  }
}

void ausgabe() {                        //empfangene Daten ausgeben
Serial.println("daten Empfangen:");
Serial.println(hoehe);
Serial.println(geschwindigkeit);
}

wenn ich jetzt z.B. 120 in den Serial Monitor eingebe und das Sende dann bekomme ich sofort folgendes zurück:

daten Empfangen:
49
50

dabei sollte er doch erst senden wenn er BEIDE werte hat.
Hoffentlich kann mir jemand weiterhelfen, höchtwahrscheinlich gibt es eine wesentlich einfachere Möglichkeit die Seriellen Signale auszuwerten.

Gruß Max

Hallo,
ohne Gewähr, aber so ähnlich sollte es gehen:

void setup() {
  Serial.begin(9600);
}
void loop() {
  char c,c1;
  float hoehe, spannung, temperatur, geschwindigkeit;
  int result = 0;  

  if (Serial.available() > 0 ) {       //wenn Serielle Daten verfügbar sind...
    // warten auf Schlüsselzeichen T,H,S oder V
    c = Serial.read();
    switch (c) {
    case 'T' : if (ReadValue(&temperatur)) result |= 1;
                  break;
    case 'H':  if (ReadValue(&hoehe)) result |= 2;
                  break;
    case 'V':  if (ReadValue(&spannung)) result |= 4;
                  break;
    case 'S':  if (ReadValue(&geschwindigkeit)) result |= 8;
                  break;
    }
    // alle Werte empfangen, dann ausgeben
    if (result == 15) {
      result = 0;
      Serial.println("Daten empfangen: (H,S,T,V)");
      Serial.println(hoehe);
      Serial.println(geschwindigkeit);
      Serial.println(temperatur);
      Serial.println(spannung);
   }
}


float ReadValue(float *val;) {
  // eine Float mit führenden = empfangen
  char c;
  float sign = 1.0;
  float dp = 0.0;
  int starttime; // für Timeout

  val = 0.0;
  starttime = millis();
  // nächstes Zeichen mUss '=' sein
  while (Serial.available() <= 0) {}; // auf Zeichen warten
    c = Serial.read();
    if (c != '=') return false;
    do {
      while (Serial.available() <= 0) {}; // auf Zeichen warten
      c = Serial.read();
      if (c == '-') sign *= -1.0; // Vorzeichen
      else if (c == ',' || c == '\n' || c == '\r') { // Ende des Wertes
        val = val * sign;
        return true;
      }
      else if (c == '.') dp = 10.0; // Dezimalpunkt
      else if (c >= '0' && c <= '9') { // Ziffer
        if (dp == 0)
          // Vorkommastelle
          val = val * 10.0 + (float) (c-'0');
        else {
          // Nachkommastelle
          val = val * ((float) (c-'0'))/dp; 
          dp *= 10.0;
        }
      }
      else return false; // ungültiges Zeichen
    } while (millis()-starttime < 100);
    return false;
  }
}

Viel Erfolg
Michael

der Code unterscheidet sich ja schon stark von meinem :smiley: aber is ne gute lösung, wenn sie mal funktioniert. Momentan erkennt er leider die Funktion 'ReadValue' nicht und deswegen kommt auch immer ein error, sodass ich es nicht aufs Board laden kann.
Da steht immer :

error: 'ReadValue' was not declared in this scope

Ich werde mal noch weiterversuchen, den Code zum Laufen zu bringen, immerhin habe ich ihn schon verstanden. Ich melde mich wieder.

Gruß Max

[EDIT]
hmmm ich bekoms nicht hin. Der Compiler hat absolut keine Ahnung was 'ReadValue' ist und gibt desshalb besagte Fehlermeldung aus. Allerdings hab ich keine Ahnung wiso er es nicht erkennt. Ich hab schon des Öfteren Codes geschrieben mit eigenen Funktionen, ich kann keinen Fehler finden.
Vllt. sieht jemand anders ja den Fehler im oben geposteten Code, ich leider nicht.

Gruß Max

Ich habe sowas ja noch nie probiert, aber ich befürchte der Code wird am Boden besser funktionieren wie in der Luft. Das Problem ist, daß die Verbindung früher oder später verrauscht sein wird.

Was mir dazu einfällt:

  1. Die Steuercodes sollten "out of Band" übertragen werden,

oder besser:

  1. Alle Datenpakete sollten mit Prüfsummen und/oder Fehlerkorrektur verschickt werden

Ich denke Reed-Solomon-Code – Wikipedia wäre sicher ein sehr guter Anfang. Für Anfänger aber vieleicht etwas schwierig. Ansonsten CRC: Zyklische Redundanzprüfung – Wikipedia.

Auf jeden Fall braucht es eine Möglichkeit Übertragungsfehler zu erkenen und danach sobald die Verbindung wieder OK ist den Datenstrom wieder zu synchronisieren.

Gruß, Udo

P.S. Und vieleicht ist es auch noch eine gute Idee mit einer möglichst niedrigen Baudrate zu arbeiten.

oha, da muss ich wohl erstmal testen wie das ganze in der Praxis aussieht, falls das Verrauschen der Fall sein sollte, kann ich mich immernoch einlesen und evt. eine Fehlerkorrektur "einbauen"
Allerdings würde ich gerne mit dem o.g. Problem Anfangen. Ich habe noch keine X-Bee's, sondern möchte zuerst den o.g. Code zum laufen zu kriegen, dann kann ich mich an die X-Bee's machen.

Gruß Max

Hallo twinflyer,

hab ich doch noch einen Leidensgenosse gefunden.
Ich selbst spiele noch nicht so lange mit Arduinos und versuche genau das gleiche Projekt wie du auch.
Zwei LED über XBEEs und Potis steuern geht über folgenden Code.

// SENDER

int analogValue2, analogValue5, val2, val5;

void setup()
{
  Serial.begin(19200);
}

void loop()
{
  analogValue2 = analogRead(2);
  analogValue5 = analogRead(5);

  val2 = map(analogValue2, 0, 1023, 253, 0);  
  val5 = map(analogValue5, 0, 1023, 253, 0);

  Serial.print(254, BYTE); 
  Serial.print(val2, BYTE);

  Serial.print(255, BYTE); 
  Serial.print(val5, BYTE);

  delay(150);
}
// RECIEVER

byte incomingByte, sensor1, sensor2;

void setup() 
{
  Serial.begin(19200);
  Serial.println("Ready!");

  pinMode (5, OUTPUT);
  pinMode (6, OUTPUT);

  delay(1000);
}

void loop() 
{
  if (Serial.available()) 
  { 
    incomingByte = Serial.read();
    Serial.print(int(incomingByte));
    
    if ((int(incomingByte) == 254)) 
    {
      sensor1 = Serial.read();
      Serial.print(" Sensor 1 = ");
      Serial.println(int(sensor1));
    }

    if ((int(incomingByte) == 255)) 
    {
      sensor2 = Serial.read();
      Serial.print("  Sensor 2 = ");
      Serial.println(int(sensor2));
    }
  }

analogWrite (5, sensor1);
analogWrite (6, sensor2);
}

Sollte mit Switch-Case selbst verständlich auch funktionieren. Bei meinem Code kann ich dir aber versprechen, dass er so wie er oben steh bei mir auch funktioniert.

Danke mike_pa, werde deinen Code gleich mal näher anschauen und testen.

Gruß,
Roland

cool dass es noch jemanden gibt der auch ein eigenes telemetriesystem aus bauen will.
Wenn der Code wie er oben steht (oder eben in veränderter Form) funktioniert bestelle ich die X-Bees und 2 FUNNEL. Dazu ein OLED Display, damit ich auch was sehe.
Vllt. könnten wir uns ja gegenseitig austauschen falls jemand was neues geschafft hat oder probleme hat. Wenn das ganze dann funktioniert kann man es ja evt. auf veröffentlichen, also OpenSource. Aber erstmal muss es klappen :wink:
Ich werde weiterhin versuchen den Code zum Laufen zu bringen. Wenns klappt schreibe ich es natürlich hier.

Gruß Max

Zum Thema Funnel, solltest du kurz HIER rein schauen.
Hatte schon so meine Problemchen mit den.

Zur weiteren Telemetrie Plauderei, würde ich aber einen anderen Thread auf machen. Hier geht es ja weiterhin um das Problem "Serielle Signale in versch. Variablen speichern".
Bin mit meinem Codeschnipsel ja nicht zufrieden. Ist bis jetzt nur der Anhaltspunkt, um weiter zu verbessern.

Ich hab den Code von mike_pa leider noch nicht zum laufen bekommen.

Wo wird denn die Telemetrie rein kommen?

Ich hab den Code leider auch nicht zum Laufen bekommen, immer der gleiche fehler. Der Compiler erkennt die funktion ReadValue einfach nicht.
Vielleicht kann da mal jemand mit etwas mehr erfahrung in Sachen Arduino drübergucken, ich bekomms nicht hin :frowning:

Gruß Max

PS.: Das mit der Telemetrie machen wir dann wenn wir es hinbekommen haben die Seriellen Signale zu "splitten". Dann machen wir einfach ein neues Thema auf.

Hallo an alle die mehrere Daten über XBee zum Roboter / Flugzeug etc. senden wollen.

Ich habe hier folgende Komponenten:

Sender: Arduino + XBee + Nintendo Nunchuck

Empfänger: Roboter mit zwei Motoren (derzeit noch umgebaute Servos) und einem Servo auf dem eine Funkkamera drauf ist. Dazu ein Arduino und einmal XBee.

Der Sender liest den Nunchuck aus und sendet die Werte seriell, also über XBee zum Empfänger. Dieser erkennt wann die Übertragung eines Datensatzes vorbei ist, zerlegt diesen und steuert dann die Servos. Hier der Code:

SENDER

// Roboter                 ___   ___       Draufsicht Stecker
// Version 0.2            | 1 --- 2 |      1 - Clock an Analog 5     2 - GND an Analog 2
// Befehle über Nunchuck  | 3     4 |      3 - 5V an Analog 3        4 - Data an Analog 4
// SENDER                  --------- 

#include <Wire.h>
#include "nunchuck_funcs.h"
int loop_cnt=0;
byte accx,accy,accz,zbut,cbut,joyx,joyy;  
int PowerLED = 13;         // PowerLED
 
void setup() 
{ 
  pinMode(PowerLED, OUTPUT);
  digitalWrite(PowerLED, HIGH);
  Serial.begin(57600);
  nunchuck_setpowerpins(); 
  nunchuck_init();
} 

void loop() 
{ 
    if ( loop_cnt > 50 ) { // every 100 msecs get new data
        loop_cnt = 0;
        nunchuck_get_data();
        accx  = nunchuck_accelx();     // ranges from approx 70 - 182
        accy  = nunchuck_accely();     // ranges from approx 65 - 173
        accz  = nunchuck_accelz();
        zbut = nunchuck_zbutton();
        cbut = nunchuck_cbutton(); 
        joyx = nunchuck_joyx();        // 20-115-220 links-mitte-rechts
        joyy = nunchuck_joyy();        // 36-136-232 unten-mitte-oben
        Serial.print((byte)joyx,DEC);
        Serial.print(";"); 
        Serial.print((byte)joyy,DEC);
        Serial.print(";");
        Serial.print((byte)zbut,DEC);
        Serial.print(";");
        Serial.print((byte)cbut,DEC);
        Serial.println("*");            //116;136;0;0*  <- Beispiel-Datensatz
    }
    loop_cnt++;
    delay(1); 
}

EMPFÄNGERER

// Roboter
// Version 0.2
// Befehle über Nunchuck
// EMPFÄNGER
// Bot mit Servo-Antrieb

// 116;136;0;0*

// Servo Hardware einrichten
#include <Servo.h>
Servo servo_li;  
Servo servo_re;
Servo servo_cam;

//Sonstige Hardware
int PowerLED = 13;         // PowerLED

//Kommunikation via XBee
char current = 0;            // Einzelzeichen über serial
char data[15] = "";          // Zeichenpuffer Gesamtdaten
int incount = 0;             // Zähler für Pufferzeiger
bool lineComplete = false;   // Merker ob Zeilenende erreicht wurde 
char *X = 0;                 // X-Wert vom Nunchuck aus "data"
int xWert = 0;               // integer X-Wert nach atoi Operation
char *Y = 0;                 // Y-Wert vom Nunchuck aus "data"
int yWert = 0;               // integer Y-Wert nach atoi Operation
char *Z = 0;                 // Z-Taster vom Nunchuck aus "data"
int zTaster = 0;
char *C = 0;                 // X-Taster vom Nunchuck aus "data"
int cTaster = 0;

//Werte für die Servoeinstellungen
int campos = 95;           // unten 50, oben 135
int servo_li_pos = 95;     // Servo steht bei Wert 95, größer = vorwärts
int servo_re_pos = 98;     // Servo steht bei Wert 98, kleiner = vorwärts
 
void setup() 
{ 
  servo_re.attach(9);   
  servo_li.attach(10);
  servo_cam.attach(11);
  pinMode(PowerLED, OUTPUT);
  digitalWrite(PowerLED, HIGH);
  servo_li.write(servo_li_pos); 
  servo_re.write(servo_re_pos); 
  Serial.begin(57600);
  // Serial.println("Roboter gestartet!!!");
} 
 
 
void loop() 
{ 
  while ( (Serial.available()) & (incount < 15) & (!lineComplete) )
  {
    current = Serial.read();
    if (current != 42) //ASCII 42 == '*'   // solange Zeichen lesen bis das Sternchen den Datensatz abschließt
    {
      data[incount] = current;
      incount++;
    }
    else
    {
      data[incount] = '\0'; // puffer mit NULL Zeichen abschließen, damit das Ende der Zeichenkette durch string Operationen erkannt wird
      lineComplete = true;
    }
  }
  if (lineComplete)  // Wenn der volle Datensatz gelesen wurde
  {
    digitalWrite(PowerLED, HIGH);
    //Serial.println(data); //zu testen ohne XBee kann man das board auch über die serielle konsole mit daten füttern
    daten_auswerten();
    werte_beurteilen();
    werte_einstellen();
    lineComplete = false;
    incount = 0;
    digitalWrite(PowerLED, LOW);
  }
  else if (incount >=15)
  {
    incount = 0;
    lineComplete = false;
  }
}
    

void daten_auswerten()
{
  X = strtok ( data, ";");      // 116;136;0;0*   // X = alle Zeichen vor dem ersten ";" also im Beispiel (s. vorne) '116'
  Y = strtok ( NULL, ";");                                      // Y = alle Zeichen bis zum nächsten ";" also '136'
  Z = strtok ( NULL, ";");                                      // Z = 0
  C = strtok ( NULL, "*");                                    // C = 0
  xWert = atoi (X);  //umwandlung von string in Wert (zur weiteren berechnung)
  yWert = atoi (Y);
  zTaster = atoi (Z);
  cTaster = atoi (C);  
  /*
  Serial.println(X); //Datenausgabe zur Kontrolle (können abgeschaltet werden)
  Serial.println(xWert);
  Serial.println(Y);
  Serial.println(yWert);
  Serial.println(Z);
  Serial.println(zTaster);  
  Serial.println(C);
  Serial.println(cTaster);  
  */
}

void werte_beurteilen() // entsprechend der werte den roboter steuern. AB HIER EIGENE DINGE MACHEN ;-)
{
  if ( (xWert < 135) && (xWert > 95) && (yWert < 171) && (yWert > 101)) {
    // stop
    servo_li_pos = 95;
    servo_re_pos = 98;
  }
  if ( (yWert > 171) && (cTaster == 1) && (zTaster == 0) ) {  //vorwärts
    servo_li_pos = servo_li_pos + (yWert - 171);
    servo_re_pos = servo_re_pos - (yWert - 171);
  }
  
  if ( (yWert < 101) && (cTaster == 1) && (zTaster == 0) ) {  //rückwärts
    servo_li_pos = servo_li_pos - (101 - yWert);
    servo_re_pos = servo_re_pos + (101 - yWert);
  }
  
  if ( (xWert < 95) && (cTaster == 1 ) && (zTaster == 0) ) {  //links
    servo_li_pos = 95; 
    //servo_re_pos = servo_re_pos + (110 - xWert);
  }
  
  if ( (xWert > 135) && (cTaster == 1) && (zTaster == 0) ) {  //rechts
    servo_re_pos = 98; 
  }
    
  if ( (yWert > 140) && (cTaster == 0) && (zTaster == 1) ) {  //Cam up
    campos = campos + 1; 
  }

  if ( (yWert < 132) && (cTaster == 0) && (zTaster == 1) ) {  //Cam down
    campos = campos -1; 
  }  
  if (campos > 135) { campos = 135;}
  if (campos < 50) { campos = 50;}  
                // 2  - vorwärts schnell
           /*       Serial.println("move fast");
                  servo_li_pos = 160;
                  servo_re_pos = 20;

            // w  - vorwärts
                  Serial.println("move");
                  servo_li_pos = 96;
                  servo_re_pos = 97;
                
            // stop
                  servo_li_pos = 95;
                  servo_re_pos = 98;
                
                // s  -  rückwärts
                  Serial.println("back");
                  servo_li_pos = 93;
                  servo_re_pos = 99;
                
                // x  -  rückwärts schnell
                  Serial.println("back fast");
                  servo_li_pos = 20;
                  servo_re_pos = 160;
                
                // a  -  links
                  Serial.println("left");
                  servo_li_pos = 95;
                  servo_re_pos = 97;
                
                // d  -  rechts
                  Serial.println("right");
                  servo_li_pos = 96;
                  servo_re_pos = 98;
               
                // +
                  Serial.println("Cam up");
                  campos = campos + 1;
                
                // -
                  Serial.println("Cam down");
                  campos = campos - 1;
                if (campos > 135) { campos = 135;}
                if (campos < 50) { campos = 50;}
      */
}

void werte_einstellen() // Die empfangenen werte wurden ausgewerten und entschieden was der bot machen soll. nun werden die werte eingestellt
{
  servo_li.write(servo_li_pos); 
  servo_re.write(servo_re_pos); 
  servo_cam.write(campos); 
}

Ich habe noch ordentlich Kommentare eingefügt. Denke vieles (auch der funktionen) kann gelöscht werden. Wenn Bedarf besteht kann ich den Code auch noch einmal nur für die Sende- / Empfangsroutine posten. So war es aber einfacher :wink:

Hoffe es hilft euch. Wenn ich mal wieder Zeit habe kann ich auch gerne Bilder und evtl. Videos machen.

Lieben Gruß
Poldi

VIIIIIIEEEEEELEN DANK FÜR DEN CODE!
Endlich hab ich es geschafft die Seriellen Signale zu teilen. Dabei sehen die gesendeten Sognale folgendermaßen aus:

AAA-BBB-CCC-DDD*

Die werte werden dann einzeln durch die Konsole ausgegeben. Das funktioniert alles und so muss es dann auch mit den X-Bees funktionieren. Sobald ich wieder Geld habe (schüler) Kommt die Basisausrüstung für mein Telemetriesystem her :smiley:

Gruß Max