Retrieving numbers from the serial communication

I am programming a basic G-code interpreter, and am currently working through the serial parsing for G0 and the x, y, and z coordinates. The coordinates that follow x, y, and z can be of multiple decimals and characters, so i created a loop that adds them all into one double variable. Which works perfectly for numbers like 385, but when I send 5.6 for example it only sends back 5.00. Even though i know that the part of my code where the value is updated runs.

``````else if(c == 'X') {
//Serial.println("x");
multiplier = 1;
dec_found = false;
x_co = 0;

while(true) {

if(isWhitespace(c) || c == '\n') break; //End of G command

else if(isPunct(c)) {    //If punctuation is found
Serial.println("dec");
multiplier = 0.1;
dec_found = true;
}
else if(isDigit(c)) {
if(dec_found == true) {
Serial.println("dec found");
Serial.println(c);
c -= 48;
c = c * multiplier;
x_co = x_co + c;
multiplier = multiplier * 0.1;
}
else {
Serial.println(c);
c -= 48;
x_co = x_co * multiplier;
x_co = x_co + c;
multiplier = 10;
}
}
}
Serial.print("X is ");
Serial.println(x_co);
}
``````

I think the problem has to do with what type of variables I am using, 'c' is a char, while x_co and multiplier are doubles. The end game of this code is to use the number stored in x_co for more arithmetic, which will be the number of steps of a motor.

If anybody can figure out a solution to it not printing the decimals that would really be appreciated, thank you.

You've left out a lot of code, but I'm going to guess "inappropriate use of integers"

I guess the solution depends on the stream of data, and what you may expect.

One approach would be to receive the entire (new-line terminated) message and then parse it looking for the X, Y and Z values in the message...

Something like this:

``````#define MAX_MESSAGE_LENGTH 32

struct XYZ{
XYZ() {
x = 0;
y = 0;
z = 0;
}
double x;
double y;
double z;
};

void setup()
{
Serial.begin(9600);
Serial.println("go");
}

void loop()
{
if (const char* newMessage = checkForNewMessage(Serial, '\n'))
{
XYZ incomingCoordinates;
char buffer[16];
if (strstr(newMessage, "X"))
{
strcpy(buffer, strchr(newMessage, 'X') + 1);
incomingCoordinates.x = atof(buffer);
}
if (strstr(newMessage, "Y"))
{
strcpy(buffer, strchr(newMessage, 'Y') + 1);
incomingCoordinates.y = atof(buffer);
}
if (strstr(newMessage, "Z"))
{
strcpy(buffer, strchr(newMessage, 'Z') + 1);
incomingCoordinates.z = atof(buffer);
}
doSomethingWithXYZ(incomingCoordinates);
}
}

void doSomethingWithXYZ(XYZ& xyz)
{
Serial.println(F("new value!"));
Serial.print(F("X\t"));
Serial.println(xyz.x, 4);
Serial.print(F("Y\t"));
Serial.println(xyz.y, 4);
Serial.print(F("Z\t"));
Serial.println(xyz.z, 4);
}

const char* checkForNewMessage(Stream& stream, const char endMarker)
{
static char incomingMessage[MAX_MESSAGE_LENGTH] = "";
static byte idx = 0;
if(stream.available())
{
if(incomingMessage[idx] == endMarker)
{
incomingMessage[idx] = '\0';
idx = 0;
return incomingMessage;
}
else
{
idx++;
if(idx > MAX_MESSAGE_LENGTH - 1)
{
//stream.print(F("{\"error\":\"message too long\"}\n"));  //you can send an error to sender here
idx = 0;
incomingMessage[idx] = '\0';
}
}
}
return nullptr;
}
``````

entered:

``````X 12.34 Y 34.45 Z 45.67
``````

outputs:

``````new value!
X 12.3400
Y 34.4500
Z 45.6700
``````

BulldogLowell: One approach would be to receive the entire (new-line terminated) message and then parse it looking for the X, Y and Z values in the message...

Looks like a fancy version of Serial Input Basics :)

And, as a completely separate comment, it seems to me a great deal more sensible to interpret the GCode on a PC. I have never understood why people do that on an Arduino.

...R

Robin2: Looks like a fancy version of Serial Input Basics :)

Right, but with one or two more lessons tacked on...