Verzögerung bei der Befehleingabe bzw. Empfang

]Hallo

nach dem ich endlich durch die Hürden der Verbindung zw. Arduino und Raspberry pi mich durchgewühlt habe kommt ein neues Problem das ich ohne Hilfe nicht bewältigen kann.
Da sich meine Programmierkenntnisse auf die rudimentären Funktion beschränken hoffe ich sehr Ihr könnt mir sicherlich weiterhelfen.
Mein Problem zeichnet sich wie folgt :
Es sind mehr oder weniger 2 Programme zus geführt worden der eine steuert über die Serial2 mein Fahrzeug der andere soll die Servos drehen.
getrennt funktionieren beide Programme sehr gut nur zusammen. kommen die Befehle sehr spät an die Verzögerung kann von 2 sek bis zu 6 -7 sek dauern.
eine Steuerung des Roboters ist so nicht möglich.
hier mein Code :

/*
  Front Motor (Steering) => Channel A
 Back Motor => Channel B
 
 Since the motor shield hijacks 6 pins for the motors'
 control, they are declared in the MotorShieldR3 library.
 */
#include <MotorShieldR3.h>
#include <VarSpeedServo.h>
MotorShieldR3 yellowCar;
#define pinfrontLights    7    //Pin that activates the Front lights.
#define pinbackLights     4    //Pin that activates the Back lights.   
char command = 'x';
int velocity = 0;   

VarSpeedServo schwenk; 
VarSpeedServo kipp;

int t;
int u;
char pos1 ='0';
char pos2 ='0';
char comm[2];

void setup() 
{       
  Serial.begin(9600);
  Serial2.begin(9600);  //Set the baud rate to that of your Bluetooth module.
  //pinMode(pinfrontLights , OUTPUT);
  
schwenk.attach(40);
 kipp.attach(41); 
 

}

void loop(){
  while(Serial2.available() > 0){ 
    command = Serial2.read(); 
    //Change pin mode only if new command is different from previous.   
   
    //Serial.println(command);
    switch(command){
    case 'w':  
      yellowCar.Forward_2W(velocity = 255, velocity = 255);
      break;
    case 's':  
      yellowCar.Back_2W(velocity = 254, velocity = 254);
      break;
    case 'a':  
      yellowCar.RotateLeft_2W(velocity = 240, velocity = 240 );
      break;
    case 'd':
      yellowCar.RotateRight_2W(velocity = 240, velocity = 240);  
      break;
    case 'x':  
      yellowCar.Stopped_2W();
      break; 
    case 'b':  //Everything OFF 
      digitalWrite(pinfrontLights, LOW);
      digitalWrite(pinbackLights, LOW);
      yellowCar.Stopped_2W();
      break;         
 
        }
  }
      while (Serial2.available()) {
   Serial2.readBytes(comm, 2);
 pos1 = comm[0];
 Serial2.println(pos1);
 pos2 = comm[1];
 Serial2.println(pos2);
  
 t = pos1-'0';
 t=t*20;
 u= pos2 -'0';
 u = u*20; 
 
 if (t != 9*20)
 { schwenk.slowmove(t,90); 
 delay(100); }
 
 if (u != 9*20) 
 { kipp.slowmove(u,90); 
 delay(100); }
      }  
    
}

Die delay's habe ich schon raus gehabt ohne Erfolg
Ich tippe es liegt an der doppelten Aufruf des readbytes aber wie kann ich das umgehen?
Der eine teil des Prg. wartet auf Zeicheneingabe der andere geht über die Zahlenwerte von 1 bis 8 usw..

Bin für jede Hilfe dankbar

Gruß

Chris

Warum ruft du zweimal die Serielle Schnittstelle pro Durchlauf ab?

Wieso wartest du auch auf Zeichen? Bei sowas schließt man die Übertragung mit einem CR oder LF ab und liest dann solange Zeichen ein bis das Ende kommt. Aber nicht-blockierend! Dann kann man zwischendurch andere Dinge erledigen.
Und wieso fasst du nicht die Übertragung der Zahlen mit den Buchstaben zusammen?

Grundlegend ist es ok, wie du das machst. Wenn man nur ein oder zwei Zeichen möchte kann man die so nacheinander einlesen. Ich hänge mal eine andere Routine an, die erst mal einen ganzen String einliest. Das ist für dich eigentlich zu viel, aber es geht auch hier. Und wenn du mal komplexere Befehle brauchst kannst du das einfach erweitern. Damit könntest du z.B. problemlos sowas schicken: "w100". Für 100 cm vorwärts. Oder "l90" für 90° links rotieren

Das Test-Programm liest von Serial ein. Das kann man aber einfach beim Aufruf von serial_read() ändern.

Den Serial Monitor (bzw. dein Sende Programm) musst du so einstellen, dass am Ende in CR oder LF geschickt wird! Sonst geht es nicht.

const int SERIAL_BUFFER_SIZE = 5;
char serial_buffer[SERIAL_BUFFER_SIZE];

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

void loop()
{
  if (read_serial(Serial))
    parse_serial();
}

bool read_serial(Stream &stream)
{
  static byte index;

  while (stream.available())
  {
    char c = stream.read();

    if (c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
    {
      serial_buffer[index++] = c;
    }
    else if (c == '\n')
    {
      serial_buffer[index] = '\0';
      index = 0;
      return true;
    }
  }
  return false;
}

void parse_serial()
{
  if (serial_buffer[0] < '0' || serial_buffer[0] > '9')
  {
    Serial.print(F("Befehl: "));

    switch (serial_buffer[0])
    {
      case 'w':
        Serial.println('w');
        break;
      case 's':
        Serial.println('s');
        break;
      case 'a':
        Serial.println('a');
        break;
      case 'd':
        Serial.println('d');
        break;
      case 'x':
        Serial.println('x');
        break;
      case 'b':
        Serial.println('b');
        break;
      default:
        Serial.println(F("Unbekannter Befehl"));
    }
  }
  else
  {
    Serial.print(F("Zahl: "));
    Serial.print(serial_buffer[0]);
    Serial.print(F(" - "));
    Serial.println(serial_buffer[1]);
  }
}

Vielen Dank Serenifly für deine konstruktive Antwort,

mein Problem besteht darin, dass ich die serielle Schnittstelle nicht auslesen werde. Mein Arduino hängt per Serial2 am Raspi der wiederum einen Video Stream per cam und per PHP alles webbasierend steuerbar ist. Sprich alles was ich eingeben kann läuft über html - PHP evtl. noch per Phyton an Raspi und von dort an Arduino.

Dies sollte so einfach gestaltet werden wie nur möglich.

Gruß
Chris

@ Mutumba

wenn es nach dem gehen soll was du hier geklauterweise verzapfst dann sind solche Foren ... das ganze Netz eigentlich obsolet.

Definition Forum :
Forum (Kultur), ein realer oder virtueller Ort, wo Meinungen untereinander ausgetauscht werden können, Fragen gestellt und beantwortet werden können

Das was du eigentlich für dich selber brauchst ist eher das hier :
Forum (Platz), in der römischen Antike der Stadt- und Marktplatz, meist auch Gerichtsstätte und Ort der Volksversammlung

Zerebrator:
mein Problem besteht darin, dass ich die serielle Schnittstelle nicht auslesen werde. Mein Arduino hängt per Serial2 am Raspi

Serial oder Serial2 ist vollkommen egal. Software-seitig ist das absolut identisch

Ich hatte doch gesagt, einfach den Funktions-Aufruf ändern. Also so:

if (read_serial(Serial2))

Und schon liest du von Serial2 ein

Wichtig ist eben ein CR oder LF am Ende. Sonst wird das übertragen aber nie das Ende registriert.

hi,

das hier ist ein freundliches forum.
besonders freundlich sind (fast) alle hier zu anfängern.

und wenn sich serenifly mit seinen über 6000 posts und über 200 karmas nicht künstlich aufregt, dann steht das jemandem mit 16 (noch nie hilfreichen, wie leicht nachzulesen ist) posts ganz bestimmt nicht zu.

auch ich versuche, freundlich zu anfängern zu sein. wäre ich das nicht, hätte ich anders auf Deine ergüsse reagiert...

ach ja: herzlich willkommen hier im forum, chris. und beim nächsten mal schreibst Du halt dazu, wo Du die frage sonst noch gestellt hast.

gruß stefan

Hallo Stefan,

vollkommen Richtig dein Einwand.
Ich bekenne mich schuldig im sinne der Anklage. Hätte sagen sollen, dass ich es auch in ein anderes Forum gepostet habe.
Dadurch wollte ich nur mehr "Helfer " erreichen.

Sollte jemand Hilfe in Konstruktion oä benötigen oder am Bodensee wohnen können wir es gut und gerne bei einen Bierchen bereden.

Gruß
Chris

Basierend auf Deinem Sketch habe ich die Funktionalitäten zusammengeführt:

/*
  Front Motor (Steering) => Channel A
 Back Motor => Channel B

 Since the motor shield hijacks 6 pins for the motors'
 control, they are declared in the MotorShieldR3 library.
 */
// #include <MotorShieldR3.h>
// #include <VarSpeedServo.h>
// MotorShieldR3 yellowCar;
#define pinfrontLights    7    //Pin that activates the Front lights.
#define pinbackLights     4    //Pin that activates the Back lights.   
char command = 'x';
int velocity = 0;

// VarSpeedServo schwenk;
// VarSpeedServo kipp;

int t;
int u;
char pos1 = '0';
char pos2 = '0';
char comm[2];

void setup()
{
  Serial.begin(9600);
  //  Serial2.begin(9600);  //Set the baud rate to that of your Bluetooth module.
  //pinMode(pinfrontLights , OUTPUT);

  // schwenk.attach(40);
  //  kipp.attach(41);


}

void loop() {
  while (Serial.available() > 0) {
    command = Serial.read();
    //Change pin mode only if new command is different from previous.

    //Serial.println(command);
    switch (command) {
      case 'w':
        Serial.println("yellowCar.Forward_2W(velocity = 255, velocity = 255)");
        break;
      case 's':
        Serial.println("yellowCar.Back_2W(velocity = 254, velocity = 254)");
        break;
      case 'a':
        Serial.println("yellowCar.RotateLeft_2W(velocity = 240, velocity = 240 )");
        break;
      case 'd':
        Serial.println("yellowCar.RotateRight_2W(velocity = 240, velocity = 240)");
        break;
      case 'x':
        Serial.println("yellowCar.Stopped_2W()");
        break;
      case 'b':  //Everything OFF
        digitalWrite(pinfrontLights, LOW);
        digitalWrite(pinbackLights, LOW);
        Serial.println("yellowCar.Stopped_2W()");
        break;
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
        if (pos1 == '0') {
          pos1 = command;
        } else {
          pos2 = command;
          t = pos1 - '0';
          t = t * 20;
          u = pos2 - '0';
          u = u * 20;

          if (t != 9 * 20)
          { 
            Serial.println("schwenk.slowmove(t, 90)");
            delay(100);
          }

          if (u != 9 * 20)
          { 
            Serial.println("kipp.slowmove(u, 90)");
            delay(100);
          }
          Serial.print(pos1); Serial.println(pos2);
          pos1 = '0';
          pos2 = '0';
        }
        break;
    }
  }
}

Da ich gelernt habe, ich könnte "bösen" Code schreiben, habe ich erneut die Teufelsmaske :smiling_imp: aufgesetzt, und verwende "goto". Ich tue das, um möglichst nahe an Deinem Sketch zu bleiben. Optimierungen wie in #3 von Serenifly gezeigt, sind ja jederzeit möglich. :slight_smile:

EDIT: "Goto" gelöscht. Der Compiler kann ein richtiger Spielverderber sein ...

Man kann cases auch zusammenfassen:

case '0':
case '1':
csse '2':
   ...
   break;

@agmue

Danke für deine mühe. Leider macht der Robi keinen mux mehr ?? Habe Serial auf Serial 2 angepasst es gehen nicht einmal die Vorwärts - Rückwärts Kommandos ...

Gruß

Chris

Daß ich die Servo-Kommandos auskommentiert habe, hast Du sicher bemerkt? Hast Du alle Serial.println("schwenk.slowmove(t, 90)"); zurückgewandelt?

Hi

ja das habe ich noch getan doch leider passiert gar nix mehr ...

Gruß

Mein kleiner blauer Servo, wie er in jeder Startpackung enthalten ist, dreht sich auf pos1*20 Grad. Mein Testsketch anbei. Ich habe eine unwesentliche Änderung gemacht, die auf das Ende der Bewegung wartet:

schwenk.write(t, 20, true);

Mir hat dieses Thema eine schöne Bibliothek, die eine langsame Bewegung des Servos sehr leicht ermöglicht, bekanntgemacht. Danke dafür! :slight_smile:

Test_Forum.ino (2.42 KB)

leider genau das gleiche es bewegt sich nichts.
Vlt. liegt das daran dass es 2 servos sind die unabhängig voneinander bewegt werden.
Habe ohne die Bedingung probiert und mit servo.h statt varspeedservo.h es geht läuft alles.
Nur die Servos fahren beide gleichzeitig auf die vorgewählte Position.
Drücke ich 6 so fährt der dreh Servo UND der kipp servo auf 6.
Ziel ist dass drehen und kippen einzeln angesteuert werden sollten.

Im Anhang mein Code

TEST_2.ino (2.27 KB)

Welchen Arduino verwendest Du eigentlich?

Ich habe meinen Mega2560 mit meinem einen Servo wechselnd an Pin 40 und 41 verbunden, funktioniert wie erwartet, also kipp und schwenk sind verschieden. Mittels "true" oder "false" kann ich dann noch steuern, ob sich die Servos nacheinander oder gleichzeitig bewegen.

Dann habe ich noch meinen UNO als "Sender" verwendet und an Serial2 vom Mega angeschlossen. Auch dann fährt der servo brav an die vorgegeben Stellen und der serielle Monitor am Mega zeigt auch die richtigen Werte an. Sketche im Anhang.

Mögliche Fehlerursachen, die mir einfallen:

  1. Der Klassiker ist die zusammenbrechende Spannungsversorgung.
  2. Du bekommst über Serial2 andere Zeichen, als Du denkst und ich eintippe.
  3. Irgendwas mit dem Motor Shield.

Test_Forum_UNO.ino (263 Bytes)

Test_Forum_Mega2560.ino (2.4 KB)

Hi

ich will nicht ausschließen dass ich etwas evtl. falsch verdrahtet habe.
Doch die Servos laufen getrennt an einem 4,5 Ah Akku und werden mit einen Spannungswandler betrieben bei konstant 5,2 Volt betrieben.
Arduino Mega läuft mit einen 7,5Ah Akku hängt an einem Wandler der ihm mit 5 Volt versorgt.
Die DC Motoren laufen mit 12 Volt über einen R3 Motoren Treiber.
In den Deutschen Arduino Forum hat Rkuehle LINK eine interessante Feststellung gemacht.
Ich denke es könnte an der MotorshiledR3.h liegen.
Wo sollte ich die Tastatureigabe mit CR bzw. LF unterbrechen im Arduion Prg. oder bei der Eingabe über PHP?
Ach so der Arduino bekommt seine Befehle über Raspi.
Komisch dass alle Programme bzw Funktionen laufen wenn ich Sie einzeln beutze...

Gruß
Chris

Zerebrator:
Komisch dass alle Programme bzw Funktionen laufen wenn ich Sie einzeln beutze...

Jede Programmbiliothek wurde einzeln getestet, Deine Zusammenstellung von Bibliotheken aber sicher nicht. Daher würde ich es eher als Zufall bezeichnen, wenn es keine Beeinflussungen geben würde, da die Resourcen (Timer z. B.) begrenzt sind.

Brauchst Du alle Bibliotheken? Ich spekuliere mal, Du verwendest DC-Motoren, nicht Schritt-, da könnte man das Motorshield möglicherweise auch ohne Bibliothek ansteuern.

Wichtig wäre, Du kannst den Konflikt eindeutig benennen, dann könnte man nach Alternativen suchen.

Hi

ich habe bis auf die Servo.h alle library's entfernt leider es passiert das gleiche die beiden servos fahren zb. auf 6 ich kriege es nicht hin nur einen fahren zu lassen.

Ich denke Alternativ wäre mein PM Vorschlag besser oder was meinst du ?

Gruß
Christoph

Nun habe ich mich Deinem Bluetooth RC car Aufbau so weit es mir möglich ist, genähert. Also einen UNO zum Senden der Befehle, einen Mega2560 für das Programm zum Ansteuern von Servo und Motorshield. Ich habe dann auch die MotorShieldR3.h eingebunden, die nach meiner Einschätzung und einem flüchtigen Blick eher dem Komfort dient und außer PWM-Signalen noch digitale I/Os bedient, also "ungefährlich" erscheint. Das zeigt mein Monitor am Mega:

Programmanfang
schwenk.write(20, 20, true)
kipp.write(160, 20, true)
18
schwenk.write(160, 20, true)
kipp.write(20, 20, true)
81
schwenk.write(80, 20, true)
kipp.write(80, 20, true)
44
yellowCar.Forward_2W(velocity = 255, velocity = 255)
yellowCar.Stopped_2W()
schwenk.write(20, 20, true)
kipp.write(160, 20, true)
18
schwenk.write(160, 20, true)
kipp.write(20, 20, true)
81
schwenk.write(20, 20, true)
kipp.write(160, 20, true)
18
schwenk.write(160, 20, true)
kipp.write(20, 20, true)
81
schwenk.write(80, 20, true)
kipp.write(80, 20, true)
44

Der Servo dreht, wie er soll. Wenn ich ihn zum anderen Ausgang wechsle, dreht er in die andere Position. Das Signal sieht sauber aus:Servo01.png

Mehr fällt mir dazu momentan nicht ein. Ich habe gehört, es soll da noch ein anderes Forum geben, das man fragen könnte ... ::slight_smile:

Test_Forum_UNO.ino (339 Bytes)

Test_Forum_Mega2560.ino (2.64 KB)