[gelöst]simple Drahtloskommunikation via NodeMCU

Hallo alle zusammen.

Ich arbeite aktuell an einem “Schulprojekt” wo ich zwei Modelle für autonome Fahrzeuge “baue” (hauptsächlich programmiere). Auf jedem Fahrzeug befindet sich ein ESP (NodeMCU Board). Dann gibt es noch einen Weiteren ESP (auch wieder NodeMCU) der als Server fungieren soll und über dem die Kommunikation zwischen den beiden Clients laufen soll.

Die ESPs sollen nur Daten austauschen können, ich brauch keinerlei Web-Interface oder verschlüsselung oder sonstiges. Die ESPs sollen quasi einfach drahtlos kommunizieren.

Wie geht das am Einfachsten? Mit welcher Library etc…

Ich hab mich auch schon ein bisschen Umgeschaut, bin aber trotzdem noch neu im Esp-programmieren und netzwerken.

Sollte man das mit einem normalen Web Server machen? Mir kommt es irgendwie so vor als wäre die Kommunikation über HTTP Protokolle ziemlich umständlich für das was ich brauche?
Auch habe ich mir mal Websockets angeschaut, bin mir aber nicht sicher, ob ich das richtig verstanden habe, bzw. ob man das dafür nutzen könnte…

Beste Grüße
CodeCrafte1

schau dir die TCP Beispiele für den ESP8266 in der IDE an.

wenn die einfachen Beispiele funktionieren, schau dir JSON an.
Auch dafür findest du eine entsprechende Library

Ich hab ein Faible für udp bei sowas

Alternativ könnte man auch ein "echtes" Funkmodul nutzen.
Da ist der Programmaufwand evtl. einfacher.

Hier kann ich dann den HC-12empfehlen, der per UART angesteuert wird.
Da benötigt man keine zusätzliche Library.

noiasca:
schau dir die TCP Beispiele für den ESP8266 in der IDE an.

Ich hab jetzt das "WiFiClientBasic" Example gefunden, das sieht ziemlich nach dem aus was ich brauche. Ist es das was du meinst?
Wenn ja bräuchte ich nur noch die Server seite.
Könnte ich dabei die rechts gelistete Server Class nutzen: Arduino - WiFi

ElEspanol:
Ich hab ein Faible für udp bei sowas

Was ist das? Wie geasagt, bin noch neu beim Thema Netzwerken/Internet.

HotSystems:
Hier kann ich dann den HC-12empfehlen, der per UART angesteuert wird.

UART ist Clientbedingt schon ausgelastet. Man könnte es natürlich mit SoftwareUART machen...
Aber wir haben die NodeMCU Boards schon da, da wäre es blöd sie nicht zu nutzen.

codecrafter1:
UART ist Clientbedingt schon ausgelastet. Man könnte es natürlich mit SoftwareUART machen...
Aber wir haben die NodeMCU Boards schon da, da wäre es blöd sie nicht zu nutzen.

Auch die NodeMCU funktionieren dabei auch mit SoftwareSerial.

Sollte auch nur eine Alternative sein, wenn alles andere zu kompliziert werden sollte.

Ok und wie sieht es mit dem TCP aus, sind das die Richtigen Examples?

Was sollen die "Richtigen Examples" sein?
Ein paar mehr Infos solltest Du schon liefern.

Gruß Tommy

Tcp hat zuviel Overhead. Udp ist einfacher, schlanker und schneller, und für deinen Zweck besser.

Tommy56:
Was sollen die "Richtigen Examples" sein?

Die die ich in der vorherigen Antwort benannt habe.

ElEspanol:
Tcp hat zuviel Overhead. Udp ist einfacher, schlanker und schneller, und für deinen Zweck besser.

Ok. gibt es da schon irgendwelche vorgefertigten Examples oder muss ich mich da in den GitHub Code der Librarie lesen. Und welche Librarie nutze ich dann für UDP?

Beste Grüße
CodeCrafter1

codecrafter1:
Und welche Librarie nutze ich dann für UDP?

Wahrscheinlich wäre es angebracht mal einen Blick in die Beispiele der IDE zu werfen.

Gruß Fips

Tatsächlich war bei mir nur ein UdP-Client example für einen NTPserver. Aber auf github bin ich fündig geworden:

Dies ist ja quasi ein UdP-Server, aber könnte ich nicht dieses Sketch einfach auf alle 3 ESPs machen und bei den beiden ClientESPs einfach sagen ihr sollt nur zum ServerESP schicken und auch nur auf seine packets hören?

codecrafter1:
Tatsächlich war bei mir nur ein UdP-Client example für einen NTPserver.

So ist es bei EspCoreVersion 2.4.2. und älter!

Installiere die 2.6.3. dann hast du auch alle aktuellen Beispiele.

Edit: 2.4.2 "WifiUdpClient" - 2.6.3 "Udp"

Gruß Fips

TO: beschreib noch mal besser deine Projekt,

Auf jedem Fahrzeug befindet sich ein ESP (NodeMCU Board).
Dann gibt es noch einen Weiteren ESP (auch wieder NodeMCU) der als Server fungieren soll
und über dem die Kommunikation zwischen den beiden Clients laufen soll.

Wer initieriert die Datenübertragung?
AutoA -> AutoB oder auch AutoB->AutoA?
Was tut der ServerC dazwischen?
AutoA->ServerC->AutoB ... syncron, asyncron?
Welche Verarbeitung findet am ServerC statt?

Zeichne das mal auf was da wirklich passieren soll.

Beispiele für TCP wären

WIFIClient

/*
    This sketch establishes a TCP connection to a "quote of the day" service.
    It sends a "hello" message, and then prints received data.
*/

hab jetzt auf die schnelle nichts anderes gefunden, aber so könnte man einen Server dazu machen:

in der IDE ist das echt blöd (oder ich), nimmst halt das

WiFiManualWebServer

und statt dem http schickst halt nur deine Nutzlast retour.

Derfips:
Installiere die 2.6.3. dann hast du auch alle aktuellen Beispiele.
Edit: 2.4.2 "WifiUdpClient" - 2.6.3 "Udp"

Ok werde ich machen.

noiasca:
TO: beschreib noch mal besser deine Projekt

Also beide Fahrzeuge sollen nur mit dem ESPServer (also dem ESP dazwischen) kommunizieren. Dieser empfängt die Daten von z.B AutoA und "entscheidet" ob diese Information nur für ihn ober auch für AutoB wichtig ist und sendet die Info ggf. an AutoB. Außerdem soll der ServerESP eine Möglichkeit für mich sein in das Fahr-geschehen eingreifen zu können/ bzw. verschieden Fahrmodi auszuwählen/ beiden Fahrzeugen einen Zeitpunkt für eine synchronisierte Handlung zu schicken.

Also sollen die Fahrzeuge nur mit dem Server kommunizieren. Und der Server soll nach belieben nachrichten an ein einzelnes Fahrzeug senden können oder auch broadcasten. Wie gesagt brauche ich kein Webkram oder sonstiges; nur eine reine Datenübertragung von Strings...

Die allerertse Datenübertragung wäre dann vom ESPServer eine Abfrage ob alle Fahrzeuge anwesend sind.

noiasca:
hab jetzt auf die schnelle nichts anderes gefunden, aber so könnte man einen Server dazu machen:
ESP8266 NodeMCU TCP Socket Server Arduino Example | Circuits4you.com
in der IDE ist das echt blöd (oder ich), nimmst halt das
WiFiManualWebServer
und statt dem http schickst halt nur deine Nutzlast retour.

Ok. Danke. Ich jetzt nur noch abwägen ob ich UDP oder TCP nutze...

codecrafter1:
Dies ist ja quasi ein UdP-Server, aber könnte ich nicht dieses Sketch einfach auf alle 3 ESPs machen und bei den beiden ClientESPs einfach sagen ihr sollt nur zum ServerESP schicken und auch nur auf seine packets hören?

Wenn ich mich für UDP entscheiden sollte, könnt man das dann so machen oder wäre das ein Pfusch am Bau den man eher nicht machen sollte?

Beste Grüße
CodeCrafter1

das hat nichts mit Pfusch zu tun, sondern damit, was man benötigt.

Müssen die Infos ankommen (tcp) oder sollen sie ankommen (udp)?
Dürfen Packete verloren gehen (udp), oder nicht (tcp)?
broadcast ... da wäre udp nett - andererseits bei zwei Autos kannst du auch einfach an jeden senden.

übrigens:

Also beide Fahrzeuge sollen nur mit dem ESPServer (also dem ESP dazwischen) kommunizieren. Dieser empfängt die Daten von z.B AutoA und "entscheidet" ob diese Information nur für ihn ober auch für AutoB wichtig ist und sendet die Info ggf. an AutoB.

dann brauchst du sowieso auf jedem Device "einen Server" und einen "Client" wenn du sowohl die Daten lossenden möchtest wie auch für Daten von einem anderen empfangbar machen willst.

Ahh dankeschön. Das hilft mir sehr weiter. Jetzt teste ich erstmal ein bisschen weiter rum. Wenns funktioniert markiere ich den Thread als gelöst wenn nicht frag ich weiter :wink:

ihr schafft das sicher selber auch, aber es hat mir jetzt keine Ruhe gelassen und ich habe mir das UDP Beispiel ein wenig angepasst.

UDP empfangen
UDP periodisch senden
UDP senden, wenn was passiert
OTA für leichtere Uploads

/*
  based on UDPSendReceive.pde

  UDP Server (UDP send): listen for incomming UDP messages and acknowledge them
  UPD Client (UDP receive): send periodically status information via UDP
  read button: send information if button has changed via UDP
  OTA for easier upload
  
  by noiasca
  2020-04-14
*/

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h> // OTA Upload via ArduinoIDE

#define USE_BOARD  103                                     // set an individual number for each board

#if USE_BOARD == 103                                       // some specific settings for this board
IPAddress partnerIp(172, 18, 67, 24);
const uint32_t partnerPort = 4210;
#endif
#if USE_BOARD == 104
IPAddress partnerIp(172, 18, 67, 250);                     // some specific settings for this board
const uint32_t partnerPort = 4210;
#endif

const char* ssid = "xxxxxxxx";
const char* password = "yyyyyyyy";

const uint16_t clientIntervall = 30;                       // intervall to send data to a server in seconds. Set to 30 if you want to send data
const uint32_t localPort = 4210;                           // local port to listen on
const int button1Pin = 0;                                  // GPIO00/D3 on NodeMCU is the Flash Button - use this for testing an input
//const int output1Pin = 16;                                 // GPIO16/D0 on NodeMCU is a (sometimes red) LED on the NodeMCU Board
//const int output2Pin = 2;                                  // GPIO02/D4 on NodeMCU is the (mostly blue) LED on the ESP-12E

WiFiUDP Udp;

// check if we have received something
void checkUdpServer()
{
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    // buffers for receiving and sending data
    char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1];             // buffer to hold incoming packet,
    char ReplyBuffer[] = "ack\r\n";                            // a string to send back
    Serial.printf("Received packet of size %d from %s:%d\n    (to %s:%d, free heap = %d B)\n",
                  packetSize,
                  Udp.remoteIP().toString().c_str(), Udp.remotePort(),
                  Udp.destinationIP().toString().c_str(), Udp.localPort(),
                  ESP.getFreeHeap());

    // read the packet into packetBufffer
    int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    packetBuffer[n] = 0;
    Serial.println("Contents:");
    Serial.println(packetBuffer);

    // send a reply, to the IP address and port that sent us the packet we received
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(ReplyBuffer);
    Udp.endPacket();
  }
}

// check if it is time to trigger the UDP client
void triggerUdpClient()
{
  static uint32_t previousMillis = 0;
  if (millis() - previousMillis > 30 * 1000UL)
  {
    Serial.println(F("time to send"));
    sendUdp();
    previousMillis = millis();
  }
}

// send a UDP packet (CSV)
void sendUdp()
{
  char buffer [8];
  char sendBuffer[42] = "bo=";                   // board identifier
  itoa (USE_BOARD, buffer, 10);
  strcat(sendBuffer, buffer);
  strcat(sendBuffer, ";b1=");                    // button1Pin
  itoa (digitalRead(button1Pin), buffer, 10);
  strcat(sendBuffer, buffer);
  strcat(sendBuffer, ";ts=");                    // timestamp/uptime in seconds
  itoa ((millis() / 1000) & 0xFFFF, buffer, 10);
  strcat(sendBuffer, buffer);
  strcat(sendBuffer, "\r\n");                    // end marker (optional)
  Serial.println(sendBuffer);
  // send to the partner
  Udp.beginPacket(partnerIp, partnerPort);
  Udp.write(sendBuffer);
  Udp.endPacket();
}

// check if a button has changed
void checkButton()
{
  static byte previousButton = HIGH;
  byte button = digitalRead(button1Pin);
  if (button != previousButton)
  {
    Serial.print(F("button changed to "));
    Serial.println(button);
    sendUdp();
    previousButton = button;
  }
}

void setup() {
  Serial.begin(115200);
  Serial.print(F("\n\nUDP Server & Receiver"));
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(500);
  }
  Serial.print(F("Connected! IP address: "));
  Serial.println(WiFi.localIP());
  Serial.printf("UDP server on port %d\n", localPort);

  char buffer [8];
  char myhostname[8 + 3] = "esp";          // board identifier for OTA Upload
  itoa (USE_BOARD, buffer, 10);
  strcat(myhostname, buffer);
  ArduinoOTA.setHostname(myhostname);      // give a name to your ESP for the Arduino IDE
  ArduinoOTA.begin(); // OTA Upload via ArduinoIDE
  Udp.begin(localPort);
}

void loop() {
  checkUdpServer();    // check if we have received something
  triggerUdpClient();  // trigger a send every n seconds
  checkButton();       // check if a button has changed
  ArduinoOTA.handle(); // OTA Upload via ArduinoIDE
}

übrigens, zum testen am PC ist der Packet Sender eine praktische Sache. Emfpangs-Port in den Programm-Settings fixieren nicht vergessen.

Danke. der grobe Test (mit einem ESP und der Software) hat funktioniert, jetzt muss ich es nur noch in mein Projekt implementieren. Das OTA werde ich wahrscheinlich rausschmeißen, da auf der Fahrzeugseite schon genug Softwareaufwand anfällt...

Beste Grüße
CodeCrafter1

Jetzt kommt eine Sache, die mich sehr verwirrt. Beim ersten Test funktioniert alles wunderbar. Nun habe ich ein neues Script gemacht wo ich quasi den “ServerESP” machen wollte aber dort kommt bei der Udp Class ein Compileerror (beim anderen Script nicht).

Arduino: 1.8.5 (Windows 10), Board: "NodeMCU 1.0 (ESP-12E Module), 80 MHz, 115200, 4M (3M SPIFFS)"

D:\Schule\Seminarfach\arduino\ServerESP_test\ServerESP_test.ino: In function 'void startWiFi()':

ServerESP_test:36: error: The Udp class has been renamed EthernetUdp.
As of Arduino 1.0, the Udp class in the Ethernet library has been renamed to EthernetUdp.


   Udp.begin(localPort); //start UDP-Server

   ^

D:\Schule\Seminarfach\arduino\ServerESP_test\ServerESP_test.ino: In function 'void checkUDPServer()':

ServerESP_test:43: error: 'WiFiUdp' has not been declared

   int packetSize = WiFiUdp::Udp.parsePacket();

                    ^

ServerESP_test:50: error: The Udp class has been renamed EthernetUdp.
As of Arduino 1.0, the Udp class in the Ethernet library has been renamed to EthernetUdp.


                   Udp.remoteIP().toString().c_str(), Udp.remotePort(),

                   ^

exit status 1
The Udp class has been renamed EthernetUdp.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Die Sache die mich am meisten Verwirrt ist, dass ich dein Script und meinen erster Test ohne Compileerror funktionieren, aber dieses Script nicht…

//TODO: add UDP-TX
//TODO: add autonomus driving
//TODO: add Buttons
/*
 * WIFI UDP communication based on a script by noiasca:
 * https://forum.arduino.cc/index.php?topic=676411.15
 * 
 * 
 */

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>


//############################################# WIFI-SETUP ####################
IPAddress myIP(192,168,137,101);
IPAddress mySubnet(255,255,255,0);
IPAddress myGateway(192,168,137,200);
const uint32_t localPort = 1337;

IPAddress clientA(192, 168, 137, 21);
IPAddress clientB(192, 168, 137, 42);

const char* WiFissid = "supernicename";
const char* WiFipass = "supersecretpassword";

void startWiFi(){
  WiFi.disconnect();
  delay(20);
  WiFi.config(myIP,myGateway,mySubnet);
  WiFi.mode(WIFI_STA);
  Serial.print(F("init WiFi:")); //DEBUG
  WiFi.begin(WiFissid, WiFipass);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.'); //DBEUG
    delay(500);
  }
  Serial.print(F("Connected! IP address: ")); //DEBUG
  Serial.println(WiFi.localIP()); //DEBUG
  Serial.printf("UDP server on port %d\n", localPort); //DEBUG

  Udp.begin(localPort); //start UDP-Server
}
//############################################# UDP-RX ########################

void checkUDPServer()
{
  // if there's data available, read a packet
  int packetSize = WiFiUdp::Udp.parsePacket();
  if (packetSize) {
    // buffers for receiving and sending data
    char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1];             // buffer to hold incoming packet,
    char ReplyBuffer[] = "OK";                            // a string to send back
    Serial.printf("Received packet of size %d from %s:%d\n    (to %s:%d, free heap = %d B)\n",
                  packetSize,
                  Udp.remoteIP().toString().c_str(), Udp.remotePort(),
                  Udp.destinationIP().toString().c_str(), Udp.localPort(),
                  ESP.getFreeHeap()); //DEBUG

    // read the packet into packetBufffer
    int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    packetBuffer[n] = 0;
    Serial.println("Contents:"); //DEBUG
    Serial.println(packetBuffer); //DEBUG

    // send a reply, to the IP address and port that sent us the packet we received
    Serial.printf("send answer to %s:%d\n",Udp.remoteIP().toString().c_str(), Udp.remotePort()); //DEBUG
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(ReplyBuffer);
    Udp.endPacket();
  }
}

//############################################# UDP-TX ########################



//############################################# MAIN SECTION #################
void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN,OUTPUT);
  digitalWrite(LED_BUILTIN,HIGH);

  startWiFi();

  digitalWrite(LED_BUILTIN,LOW);
}

void loop() {
  checkUDPServer();

}
//############################################# END PRGM #####################

irgendeine Idee wieso das nun plötzlich auftaucht?

Beste Grüße
CodeCrafter1