Seeking help with serial communication

I thing I’m posting this in the right area. Feel free to direct me to the correct area if not.

I have a project where I’m trying to send X/Y coordinates from a joystick plugged into one arduino to a couple of servos that are plugged into a different arduino, over serial (both are arduino nanos). My goal is to put a Bluetooth transceiver between them to control the servos remotely, but at the moment they are directly connected. I’m pretty sure I have the sender side figured out, and it is sending the coordinates in a “###x###y” format string from one adruino to the other. However, the characters I am receiving on the receiver arduino are different than what is being sent.

With the joystick plugged into the sender unit, and at center, it is sending a string of “97x94y” after the inputs from the joystick are mapped to 0-180 for both X and Y. Not perfectly center mind you, but close enough for what I am trying to accomplish. Strangely though, “117x111y” is what is being recieved on the other end. So of course the center position for my servos ends up being even further off. I can move the joystick to either extreme, and the values on the receiver side will stop perfectly at “0x0y” or “180x180y”. I am at a loss as to why there is such a difference between what is being sent, and what is received when the joystick is at center. Any assistance would be greatly appreciated!

Sender

String coords;
String xAxisPosStr;
String yAxisPosStr;
int xAxisPosInt;
int yAxisPosInt;
int xAxisInPin = A0;
int yAxisInPin = A1;

void setup() {
// put your setup code here, to run once:
Serial.begin(38400);
pinMode(xAxisInPin, INPUT);
pinMode(yAxisInPin, INPUT);
}

void loop() {
// put your main code here, to run repeatedly:
xAxisPosInt = analogRead(xAxisInPin);
yAxisPosInt = analogRead(yAxisInPin);
xAxisPosStr = String(map(xAxisPosInt, 0, 1023, 0, 180));
yAxisPosStr = String(map(yAxisPosInt, 0, 1023, 0, 180));
coords = xAxisPosStr + "x" + yAxisPosStr + "y";
Serial.println(coords);
delay(6);
}

Receiver

#include <Servo.h>
Servo xServo;
Servo yServo;
String coords;
String xAxisPosStr;
String yAxisPosStr;
int xAxisPosInt;
int yAxisPosInt;
int xAxisOutPin = 9;
int yAxisOutPin = 10;

void setup() {
// put your setup code here, to run once:
Serial.begin(38400);
xServo.attach(xAxisOutPin);
yServo.attach(yAxisOutPin);
}

void loop() {
// put your main code here, to run repeatedly:
if(Serial.available() > 0) {
char c = Serial.read();
Serial.println(c); //troubleshooting command to view actual received characters
if(c == '\n') {
xAxisPosStr = coords.substring(0,coords.indexOf("x"));
yAxisPosStr = coords.substring(coords.indexOf("x") + 1,coords.indexOf("y"));
Serial.println(coords); //troubleshooting command to view full received string
xAxisPosInt = xAxisPosStr.toInt();
yAxisPosInt = yAxisPosStr.toInt();
xServo.write(xAxisPosInt);
yServo.write(yAxisPosInt);
xAxisPosStr = "";
yAxisPosStr = "";
xAxisPosInt = 0;
yAxisPosInt = 0;
coords = "";
delay(5);
}
else {
coords += String(c);
}
}
}

First of all, it is widely recommended to avoid the use of String (notice the capital S) due to it causing memory problems and crashing your Arduino. Use string instead. See https://playground.arduino.cc/Code/PrintingNumbers

I don't know much about serial communication, but have you seen this? http://forum.arduino.cc/index.php?topic=396450 It is in the useful links sticky at the top of this forum.

@OP

1. Re-post your sketch using code tags </> so that it appears to the style of the following example lines:

void setup()
{

}

2. If your are doing Projects for which you are copying and pasting codes, there is no complain/harm for it; but, please do respect at our times that we are spending to help you and accordingly try to write some codes of your own based on the directives given in this reply.

2. You have not connected your Sender-NANO with Receiver-NANO. So connect them using 'Software UART Ports (SUART Ports)' as the 'Hardware UART Ports (UART Port)' are engaged with their respective Serial Monitors. Add the given code lines at the appropriate places of your 'Sender Sketch' to create SUART Port named mySerial.
uart-9y1.png

#include<SoftwareSerial.h>
SoftwareSerial mySerial(4, 5); //SRX-pin = DPin-4(D4); STX-pin = DPin-5 (D5)
mySerial.begin(9600);

3. Send your to Receiver-NANO by including the following command in your Sender Sketch, which is really missing.

mySerial.print(coords);

4. Prepare a sketch for Receiver-NANO using simple if-else structure so that the x- and y-coordinate values are stored in integer variables x and y.
(1) Use the following code to store all the arrived characters (from the FIFO) into a 'NULL-byte terminated char type array' excluding the 'End Mark' character -- the 'y'.

byte n = mySerial.readBytesUntil('y', dataArray, 50);

(2) You know the character size of the x-coordinate value and accordingly manipulate the array to extract the integer value using atoi() function. Carry out similar process for the integer value of y-coordinate.

5. The following screenshots show the results of my test run using simulated value for A0 = 3.3V/2 and A1 = 3.3V.
Sm55.png

sm56.png

6. Please, post your Receiver-NANO codes.

uart-9y1.png

Sm55.png

sm56.png

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The examples work equally well with SoftwareSerial.

The technique in the 3rd example will be the most reliable. It is what I use for Arduino to Arduino communication.

You can send data in a compatible format with code like this (or the equivalent in any other programming language)

Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker

…R

Metallor:
First of all, it is widely recommended to avoid the use of String (notice the capital S) due to it causing memory problems and crashing your Arduino. Use string instead. See https://playground.arduino.cc/Code/PrintingNumbers

I don’t know much about serial communication, but have you seen this? http://forum.arduino.cc/index.php?topic=396450 It is in the useful links sticky at the top of this forum.

Thank you for the recommendation Metallor! I am still new to the Arduino IDE, and I didn’t know there was an inherent issue with String(). I’ll take itoa() into consiteration.

GolamMostafa:
@OP

1. Re-post your sketch using code tags </> so that it appears to the style of the following example lines:

2. If your are doing Projects for which you are copying and pasting codes, there is no complain/harm for it; but, please do respect at our times that we are spending to help you and accordingly try to write some codes of your own based on the directives given in this reply.

2. You have not connected your Sender-NANO with Receiver-NANO. So connect them using ‘Software UART Ports (SUART Ports)’ as the ‘Hardware UART Ports (UART Port)’ are engaged with their respective Serial Monitors. Add the given code lines at the appropriate places of your ‘Sender Sketch’ to create SUART Port named mySerial.

3. Send your to Receiver-NANO by including the following command in your Sender Sketch, which is really missing.

4. Prepare a sketch for Receiver-NANO using simple if-else structure so that the x- and y-coordinate values are stored in integer variables x and y.
(1) Use the following code to store all the arrived characters (from the FIFO) into a ‘NULL-byte terminated char type array’ excluding the ‘End Mark’ character – the ‘y’.

(2) You know the character size of the x-coordinate value and accordingly manipulate the array to extract the integer value using atoi() function. Carry out similar process for the integer value of y-coordinate.

5. The following screenshots show the results of my test run using simulated value for A0 = 3.3V/2 and A1 = 3.3V.

6. Please, post your Receiver-NANO codes.

GolamMostafa,

Thank you as well for your response.

  1. Thank you for that note. I am new to the forum and hadn’t yet learned that was an option, I will make sure to use that from now on.

2a) I wasn’t sure how to interpret this point. Was it intended just as a friendly remind regarding any code you or others may post, or are you implying the code I shared was nothing more than copy and paste from the work of others? I assure you the code I posted, and will again below, was not merely copied and pasted.

2b) I apologize for not including these details in my original post, but I have the two arduino nanos connected via the hardware TX pins connected to the RX pins, as well as have them connected to a common ground (I’ve heard that is necessary to ensure proper timing). As of right now I was just trying to get this to work while directly connected as when I have that working I intend to insert HC-05 Bluetooth modules in between them, which use the hardware serial pins to pass traffic. Does it cause issues if I plug the USB cable in to view the serial monitor? Is that why you recommended switching to the software serial?

  1. I am sending the concatenated string to the receiver via the Serial.println() command. I opted to concatenate the x an y values into a single string and send it using the “println” command as it will, from what I understand, automatically include the next line delimiter (\n) at the end of the string. Which I thought would make it easier to detect the end of the string on the receiver side. I learned that method from a video I found on YouTube. Once the receiver detects that it has pulled the new line delimiter out of the buffer it then proceeds to parse the x an y values out of the string.

Here’s the code from the sender and receiver in proper format. Hopefully it’s easier to read now :wink:

Sender

String coords;
String xAxisPosStr;
String yAxisPosStr;
int xAxisPosInt;
int yAxisPosInt;
int xAxisInPin = A0;
int yAxisInPin = A1;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(38400);
  pinMode(xAxisInPin, INPUT);
  pinMode(yAxisInPin, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  xAxisPosInt = analogRead(xAxisInPin);
  yAxisPosInt = analogRead(yAxisInPin);
  xAxisPosStr = String(map(xAxisPosInt, 0, 1023, 0, 180));
  yAxisPosStr = String(map(yAxisPosInt, 0, 1023, 0, 180));
  coords = xAxisPosStr + "x" + yAxisPosStr + "y";
  Serial.println(coords);
  delay(6);
}

Receiver

#include <Servo.h>
Servo xServo;
Servo yServo;
String coords;
String xAxisPosStr;
String yAxisPosStr;
int xAxisPosInt;
int yAxisPosInt;
int xAxisOutPin = 9;
int yAxisOutPin = 10;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(38400);
  xServo.attach(xAxisOutPin);
  yServo.attach(yAxisOutPin);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(Serial.available() > 0) {
    char c = Serial.read();
    //Serial.println(c); //Temp command to view characters as they are pulled from the buffer
    if(c == '\n') {
      xAxisPosStr = coords.substring(0,coords.indexOf("x"));
      yAxisPosStr = coords.substring(coords.indexOf("x") + 1,coords.indexOf("y"));
      Serial.println(coords); //Temp command to view full string received from buffer
      xAxisPosInt = xAxisPosStr.toInt();
      yAxisPosInt = yAxisPosStr.toInt();
      xServo.write(xAxisPosInt);
      yServo.write(yAxisPosInt);
      xAxisPosStr = "";
      yAxisPosStr = "";
      xAxisPosInt = 0;
      yAxisPosInt = 0;
      coords = "";
    delay(5);
    }
    else {
        coords += String(c);
    }
  }
}

Here’s a screen shot of the serial monitor of the sender, with the joystick resting at center, implying that it is sending a string that looks exactly like I intended it to.

Here’s a screen shot of the string after it is pulled out of the buffer of the receiver, one character at a time, and recompiled into a single string. With the joystick resting at center. Notice the x and y values do not match what the sender claims it is sending, which is the issue I am trying to resolve. If I print the characters to the monitor as they come straight out of the buffer, before being compiled, they match up with what I see after they are compiled.

If I move the joystick, which is connected to the sender, to the upper left, I get the following on the receiver.

If I move the joystick to the lower right, I get this on the receiver.

I hope this helps to convey the issue I am having a little better. Considering the compiled string on the receiver looks exactly as I would expect it to when I move the joystick out to the edges of its range, I am disinclined to believe the issue is with how I am concatenating the values into a string on the sender, or how I am compiling them back into a single string on the receiver. Otherwise I would expect the compiled string on the receiver to be off no matter where the joystick is. At first I thought it was a timing issue between the two nanos causing the receiver to misinterpret the bits coming in, but then again I would expect all of the characters to be jacked up if that were the case. Perhaps I am wrong on all accounts though, and I look forward to seeing what you guys have to say after considering the additional information.

Thank you for your time!

@OP

Thank you very much for the sound reply; we always respect your concerns. If you could follow our directives of Post#2, you would certainly come up with the results that you are expecting. Unfortunately, you have still remained attached with your String with Capital-S which is not bad but not recommended. You may very well follow the tutorial of this link to solve your programming problem.

GolamMostafa: @OP

Thank you very much for the sound reply; we always respect your concerns. If you could follow our directives of Post#2, you would certainly come up with the results that you are expecting. Unfortunately, you have still remained attached with your String with Capital-S which is not bad but not recommended. You may very well follow the tutorial of this link to solve your programming problem.

@GolaMostafa

While I appreciate your eagerness to help, I am not one to blindly follow the direction of others without asking questions and understanding why they chose to give such direction. I feel that is the best way for me to learn.

You recommended using the software serial as opposed to the hardware, as does the tutorial that was linked. Something that I am definitely not opposed to, but I would like to understand why you think I should go that route. In my previous reply I had asked for an explanation as to why using the software serial may work better (ie. plugged into the USB to view the serial monitor while using the hardware pins). I attempted to find an answer on my own, but was unable to come up with any definitive answer as to why not use the hardware. Additionally, pretty much every other tutorial I've found on serial communication uses the hardware serial without issues. I may try it tonight in an effort to humor you a bit, but I imagine I will have a whole list of additional questions if that clears up my issue ;)

Indeed I have not yet addressed the use of the Script() command. Mainly because the examples I found for using itoa() add a little bit more complexity to the sketch. Personally I would rather focus on one issue at a time. So, if that is not what is directly (or even indirectly) causing the incorrect values issue, than I'll go back and replace Script() once I get the incorrect values problem figured out.

Thanks again for your time!

It is always good to use the Hardware UART Port (UART) than the Software UART Port (SUART) if we can. But as the UART Port is engaged with Serial Monitor whxih we mainly use for debugging programs, many people including me prefer not to increase the fan-out of the UART Port by connecting another device with it; rather, they take the SUART Port as an alternative.

Why is this an Example? It is because someone has worked on it, and he has found it working. The best way of self learning is to play with things that work. One follows the steps (aka blindly) and records the results against the check list that has come with the example. Now, the learner has got the example as a great resource where every line works. He has got an opportunity to use the example as a test jig to experiment/test his ideas. The example itself works to give the answers to the questions -- why a code line is there at a particular place and what does it do? If the learner does not proceed blindly (without asking question) at the first time, he might encounter disruption in his learning due to temptation in looking back for the answers of the new questions that are not needed now to follow the example. It is better to examine the example as quickly as possible and then do the all dissections on the example during coffee time.