Integer to String conversion for bidirectional UART Connection Nano and ESP32 not working

Hi,

I have an Nano and and ESP32 connected over Serial (Serial2 for the ESP). The connection is meant to be bidirectional (the Nano should echo the data sent by the esp). The ESP is the master sending two integers of the range [-100;100] and a boolean to the Nano which is supposed to echo the data. Since using a struct to package the data didnt work, i implemented a String variant which first converts these values using sprintf(dataOutput, „%03d%03d%d“, Speed1 + 100, Speed2 + 100, DriveMode) to a char array with the size 8. (Here i translated the original range +100 to [0;200] since conversion of negative ints is problematic). The conversion works flawlessly but when the arduino splits up the array into its variables by using Speed1 = dataInput.substring(0,3).toInt() -100; (analog for Speed2) wrong values are spit out when the initial Speed was negative. So for example the Speed1 = 100; is recieved as Speed1 = 100; but the Speed1 = -50; it is recieved as Speed1 = 306; The problem only appears when the initial Speed sent by the esp was negative. So far i couldn`t find the solution of this conversion problem and i would be extremely thankful to whoever can solve the problem since neither I nor chatgpt4o could. Thanks guys!

You are unlikely to get much help unless you post the two sketches that transmit and receive the data to show what you are doing

Check the size of the array carefully. 8 bytes sounds too small and it is not a String

Then you say you use

But we have no idea what data type datainput is or where it comes from

Thanks for the fast response. Here´s the code:
Nano:

   Anschlossen an COM4 (oberster USB an Laptop)

   Datenübertragung Nano:
   Senden: Motor1Speed Motor2Speed DriveMode
   Empfangen: Motor1Speed Motor2Speed DriveMode (leftSensor) (rightSensor)
*/

// Deklaration der Variablen für die empfangenen Daten
uint8_t Motor1Speed = 0;
uint8_t Motor2Speed = 0;
uint8_t leftSensor = 0;
uint8_t rightSensor = 0;
bool DriveMode = false;

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // Konvertiere die Werte in einen String mit fester Breite
  char dataOutputString[8]; // Für 2 uint8_t-Werte und einen bool
  sprintf(dataOutputString, "%03d%03d%d", (Motor1Speed + 100), (Motor2Speed + 100), DriveMode);

  // Sende den String über die serielle Schnittstelle
  Serial.println(dataOutputString);

  // Empfange neue Daten
  if (Serial.available() > 0) {
    // Lese den eingehenden String
    String dataInputString = Serial.readStringUntil('\n');


    // Extrahiere die Werte aus dem String und konvertiere sie zurück in die entsprechenden Datentypen
    Motor1Speed = dataInputString.substring(0, 3).toInt() - 100;
    Motor2Speed = dataInputString.substring(3, 6).toInt() - 100;
    DriveMode = (dataInputString.substring(6, 7).toInt() == 1); // Konvertiere den char in bool
    Serial.println(Motor1Speed);

  }

  if (DriveMode) {
    digitalWrite(LED_BUILTIN, HIGH);
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

ESP

/*
   Angeschlossen über COM6 (USB-C Laptop)
*/

#include <esp_now.h>
#include <WiFi.h>

// Struktur für empfangene Daten
typedef struct struct_message {
  int desiredMotor1Speed;
  int desiredMotor2Speed;
  bool desiredDriveMode; // true = autonomous driving
} struct_message;

// Struktur für zu sendende Daten
typedef struct struct_response {
  int actualMotor1Speed;
  int actualMotor2Speed;
  bool driveMode; // true = autonomous driving
} struct_response;

struct_message incomingData;
struct_response responseData;

// MAC-Adresse der Fernbedienung
uint8_t remoteAddress[] = {0x10, 0x06, 0x1C, 0x41, 0xB6, 0xA0};

void sendDataToNano(int motor1Speed, int motor2Speed, bool driveMode) {
  char dataOutputString[8]; // Für drei uint8_t-Werte und einen bool
  sprintf(dataOutputString, "%03d%03d%d", (motor1Speed + 100), (motor2Speed + 100), driveMode);
  //Serial.println(dataOutputString);
  // Sende den String über die serielle Schnittstelle
  Serial2.println(dataOutputString);
}

void recieveDatafromNano() {
  if (Serial2.available() > 0) {
    // Lese den eingehenden String
    String dataInputString = Serial2.readStringUntil('\n');
      Serial.print("Input String: ");
      Serial.println(dataInputString);
      // Extrahiere die Werte aus dem String und konvertiere sie zurück in die entsprechenden Datentypen
      responseData.actualMotor1Speed = dataInputString.substring(0, 3).toInt() - 100;
      responseData.actualMotor2Speed = dataInputString.substring(3, 6).toInt() - 100;
      responseData.driveMode = (dataInputString.substring(6, 7).toInt() == 1); // Konvertiere den char in bool

      // Ausgabe der empfangenen Werte
      Serial.print("Empfangener Wert 1: ");
      Serial.println(responseData.actualMotor1Speed);
      Serial.print("Empfangener Wert 2: ");
      Serial.println(responseData.actualMotor2Speed);
      Serial.print("Empfangener Wert 3: ");
      Serial.println(responseData.driveMode ? "true" : "false");
      Serial.println("");
    

  }
}

// Callback bei Empfang
void onDataRecv(const uint8_t * mac, const uint8_t *data, int len) {
  memcpy(&incomingData, data, sizeof(incomingData));

  // Debug-Ausgabe der empfangenen Daten
  Serial.print("Received data from: ");
  for (int i = 0; i < 6; i++) {
    Serial.print(mac[i], HEX);
    if (i < 5) Serial.print(":");
  }

  //Testfunktion der USART Übertragung
  if ((incomingData.desiredMotor1Speed == 100) && (incomingData.desiredMotor2Speed == 100)) {
    incomingData.desiredDriveMode = true;
  }
  else {
    incomingData.desiredDriveMode = false;
  }

  //
  Serial.println();
  Serial.print("Motor 1 Speed: ");
  Serial.println(incomingData.desiredMotor1Speed);
  Serial.print("Motor 2 Speed: ");
  Serial.println(incomingData.desiredMotor2Speed);
  Serial.print("Drive Mode: ");
  Serial.println(incomingData.desiredDriveMode ? "Autonomous" : "Manual");


  sendDataToNano(incomingData.desiredMotor1Speed, incomingData.desiredMotor2Speed, incomingData.desiredDriveMode);

  // Beispielwerte setzen
  recieveDatafromNano();

  // Antwort senden
  esp_err_t result = esp_now_send(mac, (uint8_t *) &responseData, sizeof(responseData));

  if (result == ESP_OK) {
    Serial.println("Response sent with success");
  } else {
    Serial.print("Error sending the response: ");
    Serial.println(result);
  }
}



// Initialisierung und Hauptloop
void setup() {
  Serial.begin(115200);
  Serial2.begin(9600, SERIAL_8N1, 16, 17); // Serielle Verbindung über Serial1 zum Nano mit Pin 16 (TX) und 17 (RX)

  // WiFi initialisieren
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Callback für Empfang setzen
  esp_now_register_recv_cb(onDataRecv);

  // Peer hinzufügen
  esp_now_peer_info_t peerInfo;
  memset(&peerInfo, 0, sizeof(peerInfo));
  memcpy(peerInfo.peer_addr, remoteAddress, 6);
  peerInfo.channel = 0; // Default channel
  peerInfo.encrypt = false;

  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }
}

void loop() {
  // In der Hauptschleife ist nichts zu tun, alles wird im Callback abgewickelt
}

might be better to fix that..

remember the esp32 is 32 bits, so native types can have different sizes..
your ints on esp32 are 32 bits and on the nano (depends on the nano) they could be 16 bits..
structures should also be packed..

typedef struct __attribute__((__packed__)) struct_message {
  int16_t desiredMotor1Speed;
  int16_t desiredMotor2Speed;
  byte desiredDriveMode; // true = autonomous driving
} struct_message;

would be better..

let me know, if you prefer I'll look through the string code..

good luck.. ~q

Thanks, i havent considered the board specific int sizes. But having changed that didnt improve the result. I would be honored if you had a look into the string conversion

Alright i found the solution. In the nano code i used the datatype uint8_t for the integers which converted the negative values to positive... The connection works flawlessly now. Huge thanks to all helpers!

1 Like

lol, you need a separator..
maybe like a comma , between the 2 numbers..
don't see any issue when number are positive but yeah your off when numbers go negative..

Test Case in Simmulator..

~q

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.