Mobilen Roboter mit Arduino UDP steuern

Hallo allezusammen

Ich bin gerade dabei eine Programm zu entwickeln, dass in der Lage sein soll einen mobilen Roboter mittels UDP zu steuern. Hierfür verwende ich einen Arduino UNO und ein WiFi-Shield. Der Roboter verfügt über ein eigenes WLan Netzwerk mit dem ich den Arduino verbinden möchte und über dass anschließend die Nachrichten ausgetauscht werden sollen.

Als Vorlage meines Arduino Programmes verwende ich ein bereits vorhandenes C#-Programm. Das C#-Programm ist bereits mehrfach getestet worden und läuft auch perfekt, nur leider ist es ein Konsollen-Prgramm, dass heißt ich brauch immer meinen Laptop um den Roboter zu steuern, daher jetzt die Idee mit dem Arduino. Die Befehle müssen hierbei als ASCII-formatierter String an den Roboter über das UDP gesendet werden.

Aufgebaut ist ein Befehl für den Roboter folgender Maßen:
1 SQ:10 X:0 Y:0

Jetzt zu meinen beiden Fragen:

  1. In dem C#-Programm verwende ich ein byte-Array. Initialliziert wird dieses in C# von mir folgendermaßen:
byte[] sendbuffer;

Dieses Array benutze ich um die Befehle an den Roboter zu senden. Verwende ich den selben Code in der Arduino-IDE bekomme ich folgende Fehlermeldung

Test.ino: In function 'void loop()':
Test:40: error: expected unqualified-id before '[' token
Test:46: error: 'sendbuffer' was not declared in this scope
Test:46: error: invalid cast from type 'String' to type 'byte {aka unsigned char}'
expected unqualified-id before '[' token

Mein Idee war also es so umzuschreiben:

String msg = "";
byte sendbuffer[sizeof(msg)];
int seqencenr = 0;
String seqencenr_string = String (seqencenr);
msg = "1 SQ:" + seqencenr_string + " " + message;

.
Ich bin mir nur unsicher ob das Array somit groß genug ist

  1. Meine zeite frage betrifft ebenfalls das Sendbuffer-Array. In C# ist es möglich den String msg ASCII-zuformatieren. Hierbei verwende ich diesen Code:
sendbuffer = Encoding.ASCII.GetBytes(msg);

Gesendet wird anschließend einfach nur das gesamte Array sendbuffer. Wie ich die bei einem Arduino machen könnte habe ich leider nicht gefunden.

Ich hoffe jemand kann mir bei den beiden Fragen helfen. Ich danke auf jeden Fall schon einmal im Vorraus.

Dieses Array benutze ich um die Befehle an den Roboter zu senden. Verwende ich den selben Code in der Arduino-IDE

Weil C++ hier eine leicht andere Syntax hat wie C#. In C/C++ geht es so:

byte buffer[size];

Generell verhalten sich Arrays in C/C++ auch vollkommen anders als in C#. In C# sind Arrays wie alles andere auch ein Objekt. In C/C++ sind es nicht viel mehr als Zeiger und reservierter Speicher.

String msg = "";
byte sendbuffer[sizeof(msg)];

Das ist Schwachsinn. Dein String Objekt hat die Länge 0. Und sizeof() liefert dir die Größe des kompletten Objekts in Bytes! Also inklusive interner Variablen! sizeof() kannst du mit reinen Arrays machen. Aber nicht mit String Objekten. Ich habe das mal spaßhalber ausprobiert. sizeof() liefert hier 6 Bytes. Also genau was man erwartet, da die Klasse einen Zeiger auf das Array enthält (welches nicht existiert da der String leer ist) und zwei ints. Jede Variable ist 2 Bytes. 3 * 2 = 6.

Wenn es unbedingt die String Klasse sein muss und du an das interne char Array kommen musst, gibt es dafür die c_str() Methode:

Das liefert dir einen const Zeiger auf das interne Array. Man braucht also für den reinen Lese-Zugriff kein extra Array.

Wie ich die bei einem Arduino machen könnte habe ich leider nicht gefunden.

UDP Doku durchlesen:

Also einfach so:

void loop() 
{
  String test = "blah" + (String)5 + "string";
 
  sendUDP(test.c_str());
 
  delay(1000);
}

void sendUDP(const char* str)
{
  Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
  Udp.write(str);
  Udp.endPacket();
}

Nicht getestet!

Wobei das auch völlig ohne die String Klasse geht. UDP unterstützt auch die print() Methode. Man muss also gar nicht alles in einem String haben:

void loop() 
{
  sendUDP(0, 1, 2);
}

void sendUDP(int sequence, int x, int y)
{
  Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); 
  Udp.print(F("1 SQ:"));
  Udp.print(sequence);
  Udp.print(F(" X:"));
  Udp.print(x);
  Udp.print(F(" Y:"));
  Udp.print(y);
  Udp.endPacket();
}

Das ist das vernünftigste was man machen kann.

@Serenifly danke erstmal für die Tipps.

Dass es eine "schwache" Idee war mein sendbuffer Array mit der Größe eines Strings zu initialisieren hab ich mir schon gedacht. War auch nur eine Idee um einmal zu testen, ob es in dieser Weise funktionieren könnte. Ist auch schon ausgebessert worden. Danke vielmals hierfür.

Nur bei dem zweiten Teil meiner Frage sehe ich noch nicht ganz durch. Darum würde ich, dass gerne kurz durchgehen ob ich alles so richtig verstanden habe.
In C# übersetzt mir die Methode Encoding.ASCII.GetBytes() meinen String in eine Folge von Bytes.
Wenn ich die Dokumentation richtig verstanden habe kann ich mit UDP.write ein Buffer-Array senden und muss der Funktion nur das Array und die Größe dieses übergeben. Für die Übertragung des Buffers wird aber verlangt, dass das Array aus einer Bytefolge besteht. Daher schlägst du mir vor die c_str()-Methode zu benutzen.
Und hier hackt es bei mir. Laut Doku konvertiert c_str() den Inhalt eines Strings in einen nullterminierten String nach C-Stil. Aber erhalte ich dadurch den geforderten ASCII-formatierten String? Hier bin ich mir einfach nicht sicher.

Auf dem Arduino gibt es nur ASCII Strings. In C# musst da aufpassen weil .NET Unicode verwendet und daher jedes Zeichen 2 Bytes hat. Das ist der Grund weshalb du da explizit ASCII angeben musst. Du kannst das wie gesagt nicht direkt vergleichen.

Laut Doku konvertiert c_str() den Inhalt eines Strings in einen nullterminierten String nach C-Stil.

Genau-genommen wird da nichts konvertiert. Die String Klasse verwaltet intern ein char Array, das du über Methoden manipulierst. c_str() liefert dir einen Zeiger auf dieses Array, mit dem du lesend darauf zugreifen kannst. Es wird also kein extra Speicher gebraucht.

Wenn ich die Dokumentation richtig verstanden habe kann ich mit UDP.write ein Buffer-Array senden und muss der Funktion nur das Array und die Größe dieses übergeben

Die Größe ist bei einem C String gar nicht mal nötig. Da C Strings Null-terminiert sind kann die Funktion das Ende selbst bestimmen. Das ist diese Version:
UDP.write(message);

Aber was ich dir wirklich empfehlen würde ist das ganz am Ende mit mehreren Aufrufen von print(). Dem Gerät am anderen Ende der Leitung ist es vollkommen egal ob das in einem Array steht oder nicht! Die UDP Klasse setzt dann schon korrekt um.