Go Down

Topic: ESP32 calculates floats faultily opp. to my M4 and my M3/Due (Read 2080 times) previous topic - next topic

dsyleixa

hi,
my ESP32 calculates floats faultily opp. to my M4 and my M3/Due
(Arduino IDE 1.8.8 )

e.g, after a long calculation (1264 steps) by the Feather M4 I get the result 32.843750,
whilst the Feather ESP32 calculates 54196.625
update:
I now retested by the Due, and here I also get  the result 32.843750, just like the M4.

:o

this is the relevant code:

Code: [Select]

//  Lunar Lander

 
// preprocessor defaults for time sync:
//#define SYNC_REALTIME      // real time sync; outcomment for time lapse


#if defined (SAM)
   #include "avr/dtostrf.h"   // sprintf() and dtostrf() for floats
#endif


//----------------------------------------------------
// flight control
//----------------------------------------------------
// public:
float mFuel=8200;          // fuel mass in kg for landing
float hi=15300;            // act height in m
float vHorz=1685;          // Horizontal orbital speed m/s

float sTargm=470000;       // horizontal way to target landing place

float burnPerc=0;          // user input: burnrate %
float ftilt;               // tilt horiz...vert -1...0...+1
float tiltDeg;             // tilt degrees -90°...0...+90°

//----------------------------------------------------
// private:
float ti=0.0, dt=0.5;       // act time, delta time in sec

const float g=1.62;               // Moon gravity
const float MoonRad=3476000/2.0;  // Moon radius
const float mLander=6500;         // lander mass in kg with launch fuel
const float Isp=3050;             // Rocket engine Specific Impulse
const float FBrake=45000;         // Rocket engine max Propulsion Force

float burnMax=FBrake/Isp;   // absolute max fuel burnrate
float mTotal=mLander+mFuel; // brutto weight with full tanks 
float rBrake;               // user Rocket brake force 100%, percentual
float dFuel=0;              // delta fuel
float burnf=0;              // burnrate factor 0.0 ... 1.0

float dh=0.0;               // delta height in m
float scaleH=hi/100;        // scaler for tft.hight=100%
float vVert=0.0;            // Impact speed in m/s   
float accVert=0;            // vertical accel (sum)
float accBrake=0;           // acc by break rockets
float fCentrifug=0;         // centrifugal force by orbital speed
float accCentrif=0;         // centrifugal accel by orbital speed

float sHorzm=0.0;           // horizontal way flown in m



//----------------------------------------------------
// Serial LogBook
//----------------------------------------------------
void LogBook(){
   char sbuf1[50], sbuf2[50] ;   
   char* headline1 = "t.sec  hi.m vVert vHoriz   ";
   char* headline2 = "Burn tilt    brake acc  Fuel TBase.m";
   
   Serial.print(headline1);
   Serial.println(headline2);
   
   sprintf(sbuf1,    "%5.1f %5d %4d  %4d     ",
                    ti, (int)hi, (int)vVert, (int)vHorz);
   sprintf(sbuf2,    "%3d%% %4d     %3.1f %4.1f %5d %f",
                    (int)burnPerc, (int)(ftilt*90), accBrake, accVert,
                    (int)mFuel, (float)(sTargm-sHorzm));
                   
   Serial.print(sbuf1); Serial.println(sbuf2); 
   Serial.println(); 
}



uint32_t dtime;

//----------------------------------------------------
// Lander Move
//----------------------------------------------------
void LanderMove() { 
   static float t0=ti;     
   
   dtime=millis();
   if(hi>0) {

      // Burn Ratio:
      // 100 = 100% == full brake power
      //  50 =  50% == half brake power
      //  0  =  0%  == zero brake power
      //  or anything in between
      //
      // 100% BURN RATIO (BRAKE  POWER)
      //     => 45000kN propulsion force
      //     => 14,75 kg Fuel burn per second
      //     => brake accelation = 3m/s²
     
      // XEROX Board Computer program, debug:   
      if( sHorzm<15600.0) burnPerc=0;  //  sHorzm<15600   
      else
      if( vVert>60||vHorz>30 ) burnPerc=100;  // 
      else
      if(vVert>50) burnPerc=65;
      else       
      if(vVert>40&&hi<3000) burnPerc=45;
      else
      if(vVert>35&&hi<1800) burnPerc=40;
      else
      if(vVert>10&&hi<1100) burnPerc=35;
      else
      if(vVert>=1&&hi<120) burnPerc=33;
      else     
      burnPerc=0;

      // calculate control

      fCentrifug=vHorz*vHorz*mTotal/(MoonRad+hi);
      accCentrif=fCentrifug/mTotal;
     
      if(mFuel==0) burnPerc=0;          // no fuel, no burn ;)     
      burnf = burnPerc/100.0;           // factor  0...1

  //  vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
      dFuel=  burnMax*burnf*dt;        // try burnrate: enough fuel?
      dFuel = min(dFuel, mFuel);       // calc available rest fuel
     
      burnf = (dFuel/burnMax)/dt;       // re-calc burnrate by rest fuel
      burnPerc = burnf*100;
     
      rBrake= FBrake*burnf;           // rel brake force 
      accBrake= rBrake/mTotal;        // rocket brake acceleration
     
      mFuel = max(mFuel-dFuel, (float)0);     // rest fuel >=0         
      mTotal= mLander+mFuel;          // new total mass   
 
      if(vVert>=5  ) {
        if(vVert>=40 && vHorz>2 )  ftilt=0.65; // 58.5°
        else
       
        if(vVert>=30 && vHorz>2 )  ftilt=0.75; // 67.5°         
        else
        if(vVert>=20 && vHorz>2 )  ftilt=0.80; // 72.0°                 
 
        else
        if(vHorz<=2 && vHorz>=-2) ftilt=0.0;
        else       
        if(vHorz<0)    ftilt=0.0;
   
        else ftilt=0.85;    // 76.5°         
      }
      else
      if(vVert<5&&vHorz>20 )  ftilt=1;
      else ftilt=0;

      accVert = g - (1-abs(ftilt))*accBrake -accCentrif;
      vVert = vVert + accVert*dt;        // fractional vertical brake
     
      if(vHorz>0)
      vHorz = vHorz - (ftilt)*accBrake*dt;   // fractional horizonal brake

      //  vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
      sHorzm = sHorzm + vHorz*dt;            // horizontal way flown     
      dh = 0.5*accVert*dt*dt + vVert*dt ;    // delta height by res. grav+centrifug.+brake acc.
      hi = hi-dh;                            // new resulting height

      //-----------------------------------------------         
      // pause
      #ifdef SYNC_REALTIME 
         while( millis()-dtime < dt*1000 ); 
      #endif   
      //-----------------------------------------------
               
      ti+=dt;       
      LogBook();
      t0=ti;           
   
      //-----------------------------------------------
      // Landing specs/ratings
     
                                                     
      if ( (( hi<=0 && vVert>=5 ) && vVert<8) )   // Damage             
      { 
        Serial.println();
        Serial.println(" !! Damage !!");   
   
      }
     
      else       
      if ( hi<=0 && vVert<5 && abs(sTargm-sHorzm)>100) {  // very good Landing but way off
        burnPerc=0;               
        Serial.println();
        Serial.println("Very good but way off!");   
      }

      else       
      if ( hi<=0 && vVert<5) {               // Perfect Landing
        burnPerc=0;               
        Serial.println();
        Serial.println("Perfect Landing!");     
      }


      else 
      if ( hi<=0 )        // B L A S T
      { 
        Serial.println();
        Serial.println(" !!! B L A S T !!!");         
      }
   }   
}


//----------------------------------------------------
// setup
//----------------------------------------------------
void setup() {
  #if defined (SAM)
     asm(".global _printf_float"); // sprintf() and dtostrf() for floats
  #endif
 
  Serial.begin(115200);
  delay(2000);
  Serial.println("Serial started!");

  sHorzm=0; // way flown
 
  Serial.println();
   
  delay(dt*1000); 
 
  fCentrifug=vHorz*vHorz*mTotal/(MoonRad+hi);
  accCentrif=fCentrifug/mTotal;
  accVert=g-accBrake-accCentrif;
  LogBook(); 
}


//----------------------------------------------------
// loop
//----------------------------------------------------   
void loop(void) { 
         
   if (hi>0)  {
      LanderMove();     
   }
 
}



the questionable value is the last one in either Serial output line (TBase.m)
actually the M4 == DUE result
32.843750
is probably  the correct one...!

-------------------------
edit, update:
could be confirmed for MEGA2560 too, also 32.843750 here!

so just faulty for ESP32, both for fp32 and fp64 double as meanwhile tested.

dsyleixa

Has anyone ever heard or read such a thing and perhaps can check the calculation results and  possibly confirm either one  for M3, M4 and/or ESP32 platforms?

dsyleixa

Meanwhile, the fact that a ESP32 evaluate differently (i.e. 54196.625) from Due, M4, and Mega2560 (i.e., all 32.843750) was confirmed by another user in another forum.
Quote
(ESP32)
TBase.m
54196.625000
Anyone else here to test the code from above with a proprietary ESP32 vs. a Due or a M4?

srnet

Anyone elese here to test the code from above with a proprietary ESP32 vs. a Due or a M4?
Perhaps ask in the Expressif forums if you dont get an answer here.

Its their code.
No PMs please, they dont get answered.

dsyleixa

yes I will do so as soon as there are more people who could confirm that issue on either MCU.

meanwhile a 2nd user could confirm my result, that M4 (identically to  Due and Mega2560) evaluate to 32.843750 , differently to ESP32 (54196.625):
 
Quote
Running on a Feather M4 Express, the final value of TBase.m was 32.843750.
So I would appreciate very much if more people could  test the code from above with a proprietary ESP32 vs. a Due or a M4...!

MartinL

Hi dsyleixa,

The Arduino Zero (ARM Cortex M0+) agrees with the other ARM microcontrollers and evaluates to 32.843750. The ESP32 (WROOM32) generates 54196.625.

dsyleixa

Hi dsyleixa,

The Arduino Zero (ARM Cortex M0+) agrees with the other ARM microcontrollers and evaluates to 32.843750. The ESP32 (WROOM32) generates 54196.625.

thank you very much!
How do you think about that issue?
Actually it's not quite reasonable that ESP32 evaluates differently to (all?) other boards...?



MartinL

Hi dsyleixa,

I can only imagine that it has something to do with the ESP32's compiler. The results from the ARM and ESP32 boards seem to gradually diverge that may suggest some error in precision.

I noticed that problem still persists if the float data types are coverted to double.

dsyleixa

has the ESP32 got a hardware fpu coprocessor, like the M4?
or just software-float computations?

PS, FYI:
I just reported that already at the Espressive github repo:
https://github.com/espressif/esp-idf/issues/3405

nonetheless, more testers are highly appreciated! 8)


MartinL

Quote
has the ESP32 got a hardware fpu coprocessor, like the M4?
or just software-float computations?
I believe the ESP32 does have a single precision FPU, although there doesn't appear to be much information about it.

I found this in the ESP32-IDF (IoT Development Framework) documentation:

Quote
5.9.6 Floating Point Aritmetic
The ESP32 supports hardware acceleration of single precision floating point arithmetic (float) via Floating Point
Units (FPU, also known as coprocessors) attached to each core. The use of the FPUs imposes some behavioral
restrictions on ESP-IDF FreeRTOS.
ESP-IDF FreeRTOS implements Lazy Context Switching for FPUs. In other words, the state of a core's FPU registers
are not immediately saved when a context switch occurs. Therefore, tasks that utilize float must be pinned to a
particular core upon creation. If not, ESP-IDF FreeRTOS will automatically pin the task in question to whichever core
the task was running on upon the task's first use of float. Likewise due to Lazy Context Switching, interrupt service
routines must also not use float.

dsyleixa

hm - thank you, interesting - nonetheless, the issue is also about fp64, but that would probably not affect the 32bit-fpu.
::?

MartinL

Hi dsyleixa,

I managed to track down the bug.

After comparing the results from my Arduino Uno and ESP32 on a spreadsheet, I noticed that there was a spurious reading for the vertical acceleration (accVert variable) on the ESP32 during the 105th iteration.

It turns out that absolute abs() function in C should only be used with integers. However, it appears that while the AVR and ARM abs() function also accepts float data types, the ESP32 doesn't.

Replacing the abs() function for the equivalent floating point fabsf() function instead solves the issue. The AVR, ARM and ESP32 are now in agreement.

westfw

Nice work!  I was suspecting one of the "questionable " Arduino macros like abs(), but wasn't sure how that would fail...

dsyleixa

+1
I double that!
Great work, congratulations , and many thanks for your efforts
8) 8) 8)!

zoomx

https://github.com/arduino/reference-en/issues/362#issuecomment-478540338

Quote
I took a closer look into this issue and found that it's a bit complicated. The standard C++ and C implementations of abs() indeed don't work with float. However, Arduino has replaced that with their own macro implementation in their hardware cores:
https://github.com/arduino/ArduinoCore-avr/blob/1.6.23/cores/arduino/Arduino.h#L87-L94


Code: [Select]
#define abs(x) ((x)>0?(x):-(x))

which does work with any type. This macro will be used in all .ino files, and any other source file that #includes Arduino.h.
So maybe the ESP32 core doesn't have this macro.

Go Up