atof() bugs with incoming Serial float bytes

Hi everyone,

I have trouble with atof() while receiving two floats by serial.

Data are sent by a ESP8266 ESP12E over Serial.

Here is the code of sender side (note that data arrive from another wifi board) :

void Obtain_Infos() {

  int packetSize = Udp.parsePacket();         // Mandatory before Udp.read, it checks for the presence of a UDP packet, and reports the size
  if (packetSize) {                           // read only if there is something to read
    int len = Udp.read(packetBuffer, 255);    // read the packet into packetBufffer
    if (len > 0) {
      packetBuffer[len] = 0;
      Serial1.write(packetBuffer, 255);
    }

    Serial.println(packetBuffer);
  }
}

When opening the serial monitor, i can see that the sent packetBuffer is consistent.

-95.703125,-8.697688
-95.703125,-8.783871
-69.519043,-8.856874
-27.435303,-8.970563
-10.986328,-8.979998
2.532959,-8.974445
2.532959,-8.962143
13.671875,-8.944285
24.047852,-8.915693
45.410156,-8.738753
122.558594,-8.306061
197.967529,-7.805166
294.555664,-7.297930
294.555664,-6.995526
345.611572,-6.667926
395.050049,-6.29045

I am reading it on a teensy 3.2...

Here is the code receiver side :

void Get_Infos() {
  char msg_from_server[255];                              // for incoming serial2 data
  
  if (Serial2.available() > 0) {                       // only if data are received
    Serial2.readBytes(msg_from_server, 255);             // read the incoming bytes
    Split_Message_Into_Floats(",",msg_from_server);        //Get the Angle and angle_velocity in float
  }
}

void Split_Message_Into_Floats (char* delimiter, char* char_string) {   //delimiter is a "," the packetBuffer is the message
  char* pch;                                                            // strtok needs a pointer
  pch = strtok(char_string, delimiter);                           // strtok gives an adresss
  Sensor_Values[0] = atof(pch);
  Angle_Velocity = Sensor_Values[0]/10.0f;
  Serial.print(Angle_Velocity);
  pch = strtok(NULL, ",");                                           
  Sensor_Values[1] = atof(pch);
  Angle = Sensor_Values[1]*2.5;
  Serial.print(","); Serial.println(Angle);    
  
}

When I start to receive, first values are consitent and then, all negative values of the first float are positive instead of continuing alternate between negative and positive.

It seems atof works well at the beginning and then bugs for negative values...

A ok/nok serial datas are in picture attached.

Thanks in advance.

Print out the character strings that atof() is supposed to translate. That will tell you if the message components are correctly separated.

Also, a graph is not a good way to troubleshoot the output. Please show, or at least look at, the text output from the Teensy.

jremington:
Print out the character strings that atof() is supposed to translate. That will tell you if the message components are correctly separated.

I modified the code as follow :

void Get_Infos() {
  char msg_from_server[255];                              // for incoming serial2 data
  
  if (Serial2.available() > 0) {                       // only if data are received
    Serial2.readBytes(msg_from_server, 255);             // read the incoming bytes
    Split_Message_Into_Floats(",",msg_from_server);        //Get the Angle and angle_velocity in float
  }
}

void Split_Message_Into_Floats (char* delimiter, char* char_string) {   //delimiter is a "," the packetBuffer is the message
  char* pch;                                                            // strtok needs a pointer
 Serial.println(char_string);              // strtok gives an adresss
  Sensor_Values[0] = atof(pch);
  Angle_Velocity = Sensor_Values[0]/10.0f;
  //Serial.print(Angle_Velocity);
  pch = strtok(NULL, ",");                                          
  Sensor_Values[1] = atof(pch);
  Angle = Sensor_Values[1]*2.5;
  //Serial.print(","); Serial.println(Angle);    
  
}

aarg:
Also, a graph is not a good way to troubleshoot the output. Please show, or at least look at, the text output from the Teensy.

Here is the ouput on serial.

-177.917480,-12.991696

-158.355713,-13.149083

-140.167236,-13.287436

-107.971191,-13.609150

-89.843750,-13.696679

-69.244385,-13.764761

-49.346924,-13.812531

-49.346924,-13.850307

-29.022217,-13.877883

-8.697510,-13.885115

49.377441,-13.765173

67.840576,-13.695092

67.840576,-13.615859

86.486816,-13.527390

104.888916,-13.420498

122.528076,-13.295707

175.506592,-12.497647

189.788818,-12.304927

216.674805,-11.652788

254.364014,-10.920572

254.364014,-10.657847

267.456055,-10.388858

281.066895,-10.106810

294.982910,-9.811305

309.234619,-9.502039

348.876953,-7.840627

365.020752,-7.478646

382.171631,-7.100412

382.171631,-6.714011

400.177002,-6.319023

418.121338,-5.906490

434.967041,-5.477011

434.967041,-5.039572

444.458008,-4.597856

449.981689,-4.149108

449.981689,-3.698078

451.110840,-0.968014

448.547363,-0.520530

448.547363,-0.074803

447.082520,0.369716

422.149658,5.180186

422.149658,5.593442

412.902832,6.001635

403.350830,6.399997

357.086182,8.645551

325.317383,9.632271

305.175781,9.933918

305.175781,10.225179

281.707764,10.504398

255.035400,10.758261

225.769043,10.983896

225.769043,11.194666

194.671631,11.389666

162.445068,11.552810

162.445068,11.699677

129.943848,11.830141

96.313477,11.927416

63.262939,11.991262

-91.552734,11.863274

-91.552734,11.755928

-119.262695,11.634845

-145.538330,11.486912

-170.410156,11.313575

-239.929199,10.213023

-286.193848,9.659416

-310.302734,9.347814

-310.302734,9.024496

-335.388184,8.688984

-361.206055,8.328390

-387.268066,7.942253

-387.268066,7.543505

-498.535156,4.814594

-498.535156,4.307966

-514.801025,3.793749

-528.564453,3.265073

-555.267334,1.069680

-555.267334,0.510341

-558.593750,-0.050064

-563.812256,-1.743849

-564.147949,-2.308895

-554.504395,-2.868687

-541.198730,-3.416414

-527.709961,-3.950165

-527.709961,-4.476608

-514.648438,-4.995961

-482.666016,-6.466759

-467.498779,-6.937914

-450.714111,-7.392600

-431.182861,-7.828651

-431.182861,-8.254478

-352.539062,-10.158957

-331.726074,-10.493287

-284.423828,-11.092727

-284.423828,-11.368382

-259.185791,-11.631125

-213.714600,-12.083783

-194.396973,-12.278048

-194.396973,-12.462451

-136.047363,-12.926250

-116.455078,-13.041845

-62.133789,-13.433024

-42.633057,-13.474243

-23.498535,-13.496108

-4.943848,-13.492844

12.603760,-13.477809

77.972412,-13.193492

93.292236,-13.097007

93.292236,-12.992968

151.062012,-12.315221

165.893555,-12.146855

181.182861,-11.963614

181.182861,-11.772927

195.098877,-11.575487

207.733154,-11.364989

218.963623,-11.142789

218.963623,-10.915214

247.009277,-9.935641

256.835937,-9.676406

267.761230,-9.407076

277.801514,-9.127555

77.801514,-8.843314

17.291260,-7.320757

31.481934,-6.991875

46.527100,-6.648734

77.868652,-5.185981

88.885498,-4.800414

16.656494,-3.178992

32.281494,-1.898893

39.208984,-1.464490

45.800781,-1.023794

45.800781,-0.580275

50.744629,-0.134759

55.871582,0.315315

61.181641,0.770125

61.181641,1.227103

66.064453,3.989355

61.975098,4.445732

49.218750,5.340709

21.051025,7.480355

08.508301,7.883787

08.508301,8.280520

93.859863,8.669507

14.392090,10.409517

14.392090,10.709482

86.926270,10.995399

56.011963,11.251834

22.991943,11.476045

22.991943,11.683516

8.583984,12.419048

8.583984,12.451183

4.648438,12.466322

18.463135,12.447938

18.463135,12.413027

49.468994,12.362655

78.399658,12.282382

156.555176,11.756620

179.992676,11.572702

179.992676,11.377268

203.033447,11.170525

225.555420,10.941231

247.924805,10.689746

247.924805,10.427350

340.087891,8.869318

363.739014,8.504921

466.339111,5.495108

480.072021,5.013073

492.645264,4.518406

As you can see, it's then only positive.

I did noticed that the first 0 is absent :

6.622314,1.794966

6.530762,1.783915

6.530762,1.772920

6.225586,1.762089

5.126953,1.711056

4.455566,1.701875

4.455566,1.693038

1.190186,1.644143

0.427246,1.639010

0.427246,1.634264

.075195,1.609905

.197266,1.607748

.288818,1.605700

.624512,1.596583

.624512,1.594925

.624512,1.593269

.922607,1.583013

.800537,1.580605

.800537,1.578138

.739502,1.575642

.800537,1.573149

.800537,1.570689

.892090,1.568276

.953125,1.565942

.197266,1.554853

.197266,1.552806

.380371,1.550852

.777100,1.538247

.563477,1.536687

.563477,1.535021

.770020,1.521737

.739502,1.519276

.739502,1.516802

.617432,1.514269

.617432,1.511678

.464844,1.509012

.159668,1.506120

.159668,1.503079

2.014160,1.471305

2.014160,1.465126

2.166748,1.418928

Tell me if you need more data.

Can you limit the number of data items, so that you can reliably compare input with output? It's hard to know from the above prints, the results of processing one specific line.

aarg:
Can you limit the number of data items, so that you can reliably compare input with output? It's hard to know from the above prints, the results of processing one specific line.

I modified the code as follow, it's difficult for me to send only one data but I can print after each step.

void Get_Infos() {
  char msg_from_server[255];                              // for incoming serial2 data
  
  if (Serial2.available() > 0) {                       // only if data are received
    Serial2.readBytes(msg_from_server, 255);             // read the incoming bytes
    Serial.println(msg_from_server);
    Split_Message_Into_Floats(",",msg_from_server);       
  }
  return;
}

void Split_Message_Into_Floats (char* delimiter, char* char_string) {   //delimiter is a "," the packetBuffer is the message
  char* pch;                                                            // strtok needs a pointer
  Serial.println(char_string);
  pch = strtok(char_string, delimiter);                                 // strtok gives an adresss
  Sensor_Values[0] = atof(pch);
  Angle_Velocity = Sensor_Values[0];
  Serial.println(Angle_Velocity);
  pch = strtok(NULL, ",");                                           
  Sensor_Values[1] = atof(pch);
  Angle = Sensor_Values[1];
  Serial.println(Angle);    
  return;
  
}

The result, the problem is still present.

-246.063232,-3.483639

-246.063232,-3.483639

-246.06

-3.48

-193.786621,-4.345415

-193.786621,-4.345415

-193.79

-4.35

-174.224854,-4.524950

-174.224854,-4.524950

-174.22

-4.52

-85.418701,-5.397086

-85.418701,-5.397086

-85.42

-5.40

-68.328857,-5.468421

-68.328857,-5.468421

-68.33

-5.47

-51.727295,-5.522843

-51.727295,-5.522843

-51.73

-5.52

17.089844,-5.617798

17.089844,-5.617798

17.09

-5.62

17.089844,-5.594979

17.089844,-5.594979

17.09

-5.59

75.958252,-5.216505

75.958252,-5.216505

75.96

-5.22

87.127686,-5.129690

87.127686,-5.129690

87.13

-5.13

97.412109,-5.032246

97.412109,-5.032246

97.41

-5.03

115.997314,-4.585687

115.997314,-4.585687

116.00

-4.59

124.084473,-4.461065

124.084473,-4.461065

124.08

-4.46

131.622314,-4.328768

131.622314,-4.328768

131.62

-4.33

176.605225,-3.226693

176.605225,-3.226693

176.61

-3.23

186.340332,-3.042118

186.340332,-3.042118

186.34

-3.04

186.340332,-2.852875

186.340332,-2.852875

186.34

-2.85

195.709229,-2.659152

195.709229,-2.659152

195.71

-2.66

205.596924,-2.456011

205.596924,-2.456011

205.60

-2.46

214.965820,-2.243463

214.965820,-2.243463

214.97

-2.24

257.049561,-0.836642

257.049561,-0.836642

257.05

-0.84

270.507812,-0.572351

270.507812,-0.572351

270.51

-0.57

270.507812,-0.301618

270.507812,-0.301618

270.51

Something important I noticed : in the loop, I have a function driving a brushless motor, when i desactivate it, the problem is not present...

Here is the code, and I confirm, the problem is gone when this function doesn't run...

void Run_Motor (int motor_number, float angle_command) {

  //angle_cpr = map(angle,15,-32,163000,0);             //this map was int...
  angle_cpr = mapf(angle_command, 15, -32, 163000, 0);  // on the ball screw 12turn is max range, there is a 50/15 ratio between screw and motor, encoder is 4096 cpr so 12*50/15*4096 = 163000 max range
  // print angle_cpr to screen
  angle_cpr = (int)angle_cpr;
  odrive.TrapezoidalMove(0, angle_cpr);                 // move with vel_limit 820000 cpr/s and acc/dcc limit 8200000 cpr/s/s (limiting low inductance effect)
  //delay(10);                                          // fake speed
  return;

}

Very likely electrical noise from the motor is causing the MCU to mis-behave.

Regards,
Ray L.

Agreed. Power the motor using a separate motor power supply. You may also need to use shielded wiring for the motor power supply cables.

Don't forget to connect the grounds.

-246.063232,-3.483639

-246.063232,-3.483639

-246.06

-3.48

-193.786621,-4.345415

-193.786621,-4.345415

-193.79

-4.35

-174.224854,-4.524950

-174.224854,-4.524950

-174.22

-4.52

-85.418701,-5.397086

-85.418701,-5.397086

-85.42

-5.40

-68.328857,-5.468421

-68.328857,-5.468421

-68.33

-5.47

-51.727295,-5.522843

-51.727295,-5.522843

-51.73

-5.52

17.089844,-5.617798

17.089844,-5.617798

17.09

-5.62

17.089844,-5.594979

17.089844,-5.594979

17.09

-5.59

75.958252,-5.216505

75.958252,-5.216505

75.96

-5.22

87.127686,-5.129690

87.127686,-5.129690

87.13

-5.13

97.412109,-5.032246

97.412109,-5.032246

97.41

-5.03

115.997314,-4.585687

115.997314,-4.585687

116.00

-4.59

124.084473,-4.461065

124.084473,-4.461065

124.08

-4.46

131.622314,-4.328768

131.622314,-4.328768

131.62

-4.33

176.605225,-3.226693

176.605225,-3.226693

176.61

-3.23

186.340332,-3.042118

186.340332,-3.042118

186.34

-3.04

186.340332,-2.852875

186.340332,-2.852875

186.34

-2.85

195.709229,-2.659152

195.709229,-2.659152

195.71

-2.66

205.596924,-2.456011

205.596924,-2.456011

205.60

-2.46

214.965820,-2.243463

214.965820,-2.243463

214.97

-2.24

257.049561,-0.836642

257.049561,-0.836642

257.05

-0.84

270.507812,-0.572351

270.507812,-0.572351

270.51

-0.57

270.507812,-0.301618

270.507812,-0.301618

270.51

This looks as if you would only print two decimals (why by the way?), the values seem ok to me.

RayLivingston:
Very likely electrical noise from the motor is causing the MCU to mis-behave.

Regards,
Ray L.

That's what I was thinking too but when I do not connect the battery (with run motor function active), the problem occurs too. So it's a code question.

jremington:
Agreed. Power the motor using a separate motor power supply. You may also need to use shielded wiring for the motor power supply cables.

Don't forget to connect the grounds.

The motor is powered by a battery through odrive. Ground of each boards are connected together. Wiring are not shielded, it's true but as I said problem occurs when the battery is unplug and function running.

Whandall:
This looks as if you would only print two decimals (why by the way?), the values seem ok to me.

I understand that you can't see the problem but value should be negative at some point (i double checked with the sender).

Guis:
I understand that you can't see the problem but value should be negative at some point (i double checked with the sender).

-246.063232,-3.483639

-246.06

-3.48

-193.786621,-4.345415

-193.79

-4.35

The values I quoted are negative when needed, only rounded to two decimals, as requested by your print.

Considering that you have suggested a relationship between your main program and the motor function causing problems, it is now time to ask for your complete sketch.

aarg:
Considering that you have suggested a relationship between your main program and the motor function causing problems, it is now time to ask for your complete sketch.

I think I have found the problem, it seems the function push the cpu to its limit. I have remove the (int) cast and it now works, but the rate is low. I'll try with a teensy 3.6 and post an update.

The problem doesn't come from the atof after all.

You could post the motor function, maybe someone has some ideas.

Without power on the motors, there could be an array out of bounds. But then we have to see all the code as @aarg already wrote.

To be honest, I don't understand how this can go right.

You send 255 bytes, without checking what that data is, without checking if there is a zero-terminator at the end.
Assume that the motors cause a glitch on the serial lines, then you don't receive 255 bytes. Maybe a glitch will be accepted as a start bit, that will cause the value of 0xFF to be read. Just a single byte of 0xFF between the frames of data. Your code does not detect that.

The ReadBytes() has a default timeout of one second.
Do you know if there is a zero-terminator when the full 255 bytes are read ? (there is not).
Do you know if there is a zero-terminator when there is a timeout after some data has been read ? (there is not).
We prefer to define a protocol for the serial data. For example with a start-byte and stop-byte or a linefeed at the end, or with a checksum. Then we use our own code to read the data without the weird exeptions of the ReadBytes() function.

When you send frames of 255 bytes with a interval lower than 1 second, then the readBytes() will stay out of sync once there was a single glitch on the serial line, assuming you still have the default timeout of 1 second.