Storing Serial Values in a Variable and Interfacing with ESP-NOW

Hi All,

I'm at the very last step of a project to build a remote control car for my son, and I'm at a bit of a loss. I'm using ESP8266-E12s and ESP-NOW to send signals from the controller ESP8266 to the car ESP8266. Since the ESP8266s only have one analog in (the A0 on the controller is used for acceleration), I've hooked up a Nano to interpret the analog signal from a steering input potentiometer and send it over to the master ESP8266 via TX/RX. I can read out the steering signal from the Nano on the controller ESP8266. I can also send individual values (tested 10 and 180 for example to send over to the steering servo on the car from the controller and it operates as expected). I think the trouble is one of two things:

  1. Since it's only 1 byte, I might not have set things up to store in a way that I can use the incoming data, and it is just stuck reading the incoming signal.
  2. The TX/RX signal may not be properly converting to an int and instead could be sending/reading as an unsigned character (I'm sending values 0-255). I've tried to convert this to an integer on the controller side before sending things over to the car via ESP-NOW. I've also tried converting to integer on the car side, and neither seems to work. I'm not sure this is the main issue though as I have a print running on the car and while it is getting acceleration potentiometer information, the steering potentiometer input is either -1, 0, or 255, but those values are all static and do not change when adjusting the potentiometer.

I am unable to further troubleshoot, because when I connect the serial from the Nano to the controller ESP8266, my Serial Monitor gets flooded with the values from the Nano's potentiometer and my serial prints don't work. I tried a method to remedy this, but failed. Anyway, I really wanted to make this work, but this very last step is really throwing me for a loop.

Here's the controller ESP8266 code, I left in some comments that had previous attempts:


#include <ESP8266WiFi.h>
#include <espnow.h>
#include <Servo.h>
#include <SoftwareSerial.h>


int rawSpeed; //This is the raw input from the ESP8266 acceleration pot
int potpin;  // this is my steering potentiometer
Servo myservo; 



byte incomingData;  // define a variable to store 8 bits of data<<This is used for the TX/RX Signal

uint8_t broadcastAddress[] = { 0x30, 0x83, 0x98, 0xA5, 0x75, 0x80 };


typedef struct struct_message {
  int speeddata; //this is sending properly
  int turndata; //this is not (steering data)
} struct_message;

struct_message myData;

unsigned long lastTime = 0;
unsigned long timerDelay = 1;

void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
  /*Serial.print("\r\nLast Packet Send Status: ");
  if (sendStatus == 0){
    Serial.println("Delivery success");          
  }
  else{
    Serial.println("Delivery fail");
  }
  */
}

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);




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

  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_register_send_cb(OnDataSent);
  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
}



void loop() {
  // put your main code here, to run repeatedly:
 
  rawSpeed = analogRead(A0);

//THIS IS THE SECTION THAT IS THROWING ME---
    incomingData = Serial.read();
    potpin = incomingData;
 /* THIS IS AN ATTEMPT VARIATION--- I've tried converting to int on this side as well as the car side, but the car serial print is just not getting this data, although it prints fine on the controller side 0-255 according to potentiometer movement
if (Serial.available() > 0) {   // check if there is 1 byte available to read
    incomingData = Serial.read();  // read 1 byte of data and store it in the `incomingData` variable
    potpin = int(incomingData); 
  }
  incomingData = Serial.read();
  potpin = incomingData;
  */


  Serial.println("raw speed");
  Serial.println(rawSpeed);
  delay(100);
  Serial.println("turn data");
  Serial.println(potpin);
  delay(300);



  if ((millis() - lastTime) > timerDelay) {
    myData.speeddata = rawSpeed;
    myData.turndata = potpin;

    esp_now_send(0, (uint8_t *)&myData, sizeof(myData));
    lastTime = millis();
  }
}

Any help is greatly appreciated, thank you!

Suggest you work with just the Nano and Serial Monitor, until you're confident what you're sending is correct. Start with a timed loop, pumping a value out every 50 or 100 ms, and wiggling the pot to exercise the analog. Once you know what's being sent, you can move to the ESP with confidence.
One thing - show us the Nano code. I have a suspicion you're flooding the serial link with too much data.

1 Like

Thank you for the response! It could definitely be something with the timing. I have the values 100% reliable sending from the Nano to the ESP8266 controller though. That's all I can see on the serial monitor once I plug in the TX/RX cables though. I can't see my print statements, just a steady feed of potentiometer values from the Nano. Here's the code on the Nano:

#include <SoftwareSerial.h>

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

void loop() {
// read the value from the potentiometer
int pwmIn = analogRead(A0);

// map the potentiometer value to a valid PWM value
int pwmConv = map(pwmIn, 0, 1023, 0, 255);
Serial.println(pwmConv);

delay(100);
}

I think it would be simpler to replace one of the ESP8266 devices with a ESP32 NodeMCU which has multiple analogue inputs - the ESP32 runs ESP-NOW and can communicate with a ESP8266 so minimal code changes would be required

1 Like

You're right, that would definitely be easier. I was hoping to use this current less-than-ideal setup as a good learning experience for passing off serial values, but it really is turning into a tricky issue. I'd really like to figure out why it's not working since it's the very last step to having this work, but you're right it would definitely be less annoying to just use some different hardware!

int pwmConv = map(pwmIn, 0, 1023, 0, 255);
Serial.println(pwmConv);

You are sending an ascii character message of up to three digits and a new line terminator.

Try and read the message and convert to integer with atoi() like this

if(Serial.available())
    {
      char msg[4] = ""; // "xxx+null"
      byte num = Serial.readBytesUntil('\n',msg, 4);
      msg[num] = '\0';//null terminate
      //Serial.println(msg); //verify
      potpin = atoi(msg);  //convert to integer
    }

You can improve this by using a start marker to ensure synchronization.

int pwmConv = map(pwmIn, 0, 1023, 0, 255);
Serial.write('>'); //startMarker
Serial.println(pwmConv);

And then the Serial reading looks like this

 if(Serial.available())
    {
      char msg[4] = ""; // "xxx+null"
      if(Serial.read() == '>')
      {
      byte num = Serial.readBytesUntil('\n',msg, 4);
      msg[num] = '\0';//null terminate
      Serial.println(msg);
      potpin = atoi(msg);
      }      
    }
1 Like

I really appreciate the response! I tried both the first version and the second version and I'm getting the same result. As soon as I plug the TX in, the Serial Monitor strictly shows the input from the Nano and I cannot see any of my other Serial.print statements. It's just a flood of incoming data. When I unplug the TX, then my serial prints come through, but of course they do not have the data from the Nano. I'm also not able to read the data on the car side so it's difficult to diagnose. Also, there's one more anomaly I forgot to mention. The data sends from the nano when I hook TX to TX and RX to RX, which is very strange. When I go RX-TX and TX-RX (Nano-ESP8266) the data does not transfer. Not sure what to make of that part.
Maybe the car code will help. I'm thinking since the accelerometer data is coming through, this one should be a no brainer once it's stored correctly on the controller side, but who knows... I have everything called in the "turnmotor" function for now and haven't cleaned it up yet, but it's working.

#include <ESP8266WiFi.h>
#include <espnow.h>
#include <Servo.h>


int in1 = 13; //Declaring where our module is wired D7
int in2 = 15; //D8
int ConA = D1;// Don't forget this is a PWM DI/DO
int speed1;
//int val;    // variable to read the value from the analog pin
int turnValue;

Servo myservo;  // create servo object to control a servo




typedef struct struct_message {
    int speeddata;
    unsigned turndata;
    unsigned turndata2;
} struct_message;

struct_message myData;

void OnDataRecv(uint8_t * mac_addr, uint8_t *incomingData, uint8_t len) 
{
// Get incoming data
  memcpy(&myData, incomingData, sizeof(myData));
//  Serial.printf("%u bytes\n", myData.speeddata, len);
// Print to Serial Monitor
//  Serial.println(myData.speeddata);
//  Serial.println("");
}



 
void setup() {

  pinMode(D7, OUTPUT);
  pinMode(D8, OUTPUT);  
  pinMode(D6, OUTPUT);

  myservo.attach(D2);  // attaches the servo on pin 9 to the servo object



// Set up Serial Monitor
  Serial.begin(9600);
// Start ESP32 in Station mode
 WiFi.mode(WIFI_STA);
  WiFi.disconnect();

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

  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);


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

  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
}


void TurnMotorA(){ //We create a function which control the direction and speed
  Serial.begin(9600);
  digitalWrite(in1, LOW); //Switch between this HIGH and LOW to change direction
  digitalWrite(in2, HIGH);
  Serial.println("");
  Serial.println("pre assignment");
  Serial.print(speed1);
  speed1 = myData.speeddata;
  Serial.println("");
  Serial.println("post assignment");
  Serial.print(speed1);
  speed1 = speed1*0.2492668622; //We read the analog value from the potentiometer calibrate it
  analogWrite(ConA,speed1);// Then inject it to our motor
  Serial.println("");
  Serial.println("post adjustment");
  Serial.print(speed1);
  
  //turnValue = myData.turndata;            // reads the value of the potentiometer (value between 0 and 1023)
  //myservo.write(turnValue);                  // sets the servo position according to the scaled value
  Serial.println("");
  Serial.println(myData.turndata);
  Serial.println("turndata");
  Serial.print(turnValue);
  Serial.println("turndata2");
  Serial.print(myData.turndata2);
  delay(300);
  
}

void loop() {
  TurnMotorA(); //one function that keeps looping you can add another one with different direction or stop

}

Here's the code after I copy pasted in your code. You can see I tried the bottom version then commented out before trying the first version. Both yielded the same result. I wish I could see the serial prints to diagnose, but again I can only see the input from the Nano once I plug in the TX.

  rawSpeed = analogRead(A0);

  Serial.println("raw speed");
  Serial.println(rawSpeed);
  Serial.println("turn data");
  Serial.println(potpin);
  delay(300);
/*
 if(Serial.available())
    {
      char msg[4] = ""; // "xxx+null"
      if(Serial.read() == '>')
      {
      byte num = Serial.readBytesUntil('\n',msg, 4);
      msg[num] = '\0';//null terminate
      Serial.println(msg);
      potpin = atoi(msg);
      }      
    }
*/

if(Serial.available())
    {
      char msg[4] = ""; // "xxx+null"
      byte num = Serial.readBytesUntil('\n',msg, 4);
      msg[num] = '\0';//null terminate
      //Serial.println(msg); //verify
      potpin = atoi(msg);  //convert to integer
    }

    
  if ((millis() - lastTime) > timerDelay) {
    myData.speeddata = rawSpeed;
    myData.turndata = potpin;
    myData.turndata2 = incomingData;

    esp_now_send(0, (uint8_t *)&myData, sizeof(myData));
    lastTime = millis();
  }
}

Please post your code in code tags like in your first post.

I would advise that work out the nano to esp8266 communications before moving to other issues.

I cannot see any of my other Serial.print statements. It's just a flood of incoming data.

This makes no sense to me. With external data coming into the esp rx pin I can see all the other output in the monitor.

The data sends from the nano when I hook TX to TX and RX to RX, which is very strange. When I go RX-TX and TX-RX (Nano-ESP8266) the data does not transfer.

Again, this is something to work out before moving on. I would only connect the nano tx to the esp rx.

1 Like

Please edit your post to add code tags.

1 Like

Ok, I will work that out first. Thank you for the help.

All set, thank you for the feedback.

Thanks for the code tags.
Let's work on the Nano to Esp 8266 Serial connection first, before turning to the esp now connection between the car and the base.

First, we should take all the serial baud rates to 115200.
Second, I strongly recommend that the Nano sender use the code with the start marker '>'. I also think that the scaled analog read can be sent with just the new line terminator and not the '\r' carriage return when Serial.println() is used.

The Tx pin of the nano can only be connected to the 8266 Rx pin after the code is loaded on the 8266. If your connection is not Tx>Rx please attach a photo of your boards, as something about the pin out may be strange.
Here's my sender code recommendation.

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

void loop() {
// read the value from the potentiometer
int pwmIn = analogRead(A0);
// map the potentiometer value to a valid PWM value
int pwmConv = map(pwmIn, 0, 1023, 0, 255);
Serial.write('>');
Serial.print(pwmConv); //xxx
Serial.write('\n');
delay(100);
}  

Here's the code for the 8266 receiver. I have put the printouts together in the serial receive section so that you should be able to see all the output together. I have also taken out all the delays, as you don't want then if you are reading data every 100ms and trying to send it back out fast.

I don't quite understand the timerDelay value of 1 ms on the esp now transmission. If turn data is coming in every 100ms do you really need the data sent more frequently than that?

If everything looks good between the Nano and the 8266 we can move on to the car.

#include <ESP8266WiFi.h>
#include <espnow.h>

int rawSpeed;  //This is the raw input from the ESP8266 acceleration pot
int potpin;    // this is my steering potentiometer

uint8_t broadcastAddress[] = { 0x30, 0x83, 0x98, 0xA5, 0x75, 0x80 };

typedef struct struct_message
{
  int speeddata; 
  int turndata;   // (steering data)
} struct_message;

struct_message myData;

unsigned long lastTime = 0;
unsigned long timerDelay = 1;

void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus)
{
  /*Serial.print("\r\nLast Packet Send Status: ");
  if (sendStatus == 0){
    Serial.println("Delivery success");          
  }
  else{
    Serial.println("Delivery fail");
  }
  */
}

void setup()
{
  Serial.begin(115200);

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

  if (esp_now_init() != 0)
  {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_register_send_cb(OnDataSent);
  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
}

void loop()
{
  rawSpeed = analogRead(A0);

  if (Serial.available())  //message sent >xxx\n no \r
  {
    char msg[4] = "";  //"xxx+null"
    if (Serial.read() == '>')
    {
      byte num = Serial.readBytesUntil('\n', msg, 4);
      msg[num] = '\0';  //null terminate
      //Serial.println(msg);
      potpin = atoi(msg);
      Serial.print("raw speed ");
      Serial.println(rawSpeed);
      Serial.print("turn data ");
      Serial.println(potpin);
    }
  }
  
  if ((millis() - lastTime) > timerDelay)
  {
    myData.speeddata = rawSpeed;
    myData.turndata = potpin;
    esp_now_send(0, (uint8_t *)&myData, sizeof(myData));
    lastTime = millis();
  }
}

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