Using ESPAsyncWebServer- web browser cause crash

I use JY901 and ESPAsyncWebServer to develop a system. JY901 reports data every 50ms. The system crashed while I was browsing the web. This situation is not easily reproducible, but it does happen every day. Has anyone encountered this problem?

Hi @david163888,

welcome to the arduino-forum.
I'm pretty sure that you agree and will follow the way how to solve your problem mimimum 200 minutes faster.
This requires to invest 20 minutes of your precious time to read how to speedup solving your problems.

Directly after registering you got presented informations how to speed up solving your problem.
You should really read it.

best regards Stefan

My car won't start. Has anyone encountered this problem?

You provide absolutely NO useful information that would enable anyone to provide any assistance. If it is "crashing", there is a bug in your code. Without seeing that code, how can anyone here possibly help?

webServer.cpp
/* 
created on 2023_1020 by Richard
main features in the program
- read data from device
- send data to Google sheet 

*/

#include <Arduino.h>
#include "init.h"

// //Include for send data to internet
// #include "WiFi.h"
// //#include <WebServer.h>
// #include <ESPAsyncWebServer.h>
// #include <SPIFFS.h>
// #include <HTTPClient.h>
// #include "time.h"
// #include <ESPmDNS.h>

String parameter_val;
// below settings for send data to internet
const char* host = "SP150";
const char *set_ntpServer         = "pool.ntp.org";
const long set_gmtOffset_sec      = 28800;  //時區調整 +8
const int set_daylightOffset_sec  = 0;

/* WiFi Client data */
// const char *field_ssid      = "3E-4F-AP";        // change SSID
// const char *field_password  = "0226805501";  // change password

 const char *field_ssid      = "3E-Guest";        // change SSID
 const char *field_password  = "0226805501";  // change password

// char* set_ssid      = "simontai-2.4G";         // change SSID
// char* set_password  = "12345678";    // change password

// const char *field_ssid      = "Richard";        // change SSID
// const char *field_password  = "jfkiw93134";  // change password

/* WiFi AP data */
IPAddress AP_local_ip(192,168,10,1);
IPAddress AP_gateway(192,168,10,1);
IPAddress AP_subnet(255,255,255,0);
IPAddress local_IP;
const char *AP_ssid     = "SP150_AP";
const char *AP_password = "0226805501";

/* WebServer server data */
//WebServer server(80);
AsyncWebServer server(80);
int statusCode;
String content;
String room_id = "";

void  init_WebServer(void) {
//void WebServer( void * pvParam ) {
  //Serial.printf("WebServer program on core: %u\n", xPortGetCoreID());
/* sync server
//  server.on("/", handleRoot);
//  server.on("/about", []() {
//    server.send(200, "text/html; charset=utf-8", "是在哈囉喔?");
//  });
//  server.onNotFound([]() {
//    server.send(404, "text/plain", "File NOT found!");
//  });
//
//  server.begin();
*/
 /* Async server */
  server.serveStatic("/", SPIFFS, "/www/").setDefaultFile("index.html");
  server.serveStatic("/img", SPIFFS, "/www/img/Poseidon.png");
  server.serveStatic("/favicon.ico", SPIFFS, "/www/icon_result.ico");  
  // server.serveStatic("/favicon.ico", SPIFFS, "/www/favicon.ico");
  server.serveStatic("/survival", SPIFFS, "/www/").setDefaultFile("survival.html");

  //  ================

  server.on("/degree_quota", HTTP_GET, [](AsyncWebServerRequest * req) 
  {
    int16_t val;
    //Serial.print("get degree_quota\n");   
    if (req->hasParam("degree_quota")) {
      AsyncWebParameter* p = req->getParam("degree_quota");
      parameter_val = p->value();     
      //Serial.print("get degree_quota = " + parameter_val +"\n");        
      //degree_quota = (int16_t)parameter_val.toInt();  
      val = (int16_t)parameter_val.toInt();
      if ((val >= 0) && (val <= 16))
      {
        reserved_data.degree_quota = (int16_t)parameter_val.toInt();  
      }
      set_degree_quota();
    }
  });

  server.on("/degree_quota_now", HTTP_GET, [](AsyncWebServerRequest * req) {
    int16_t val = degree_quota; 
    //uint16_t val = 99;
    //Serial.print("get degree_quota_now\n");    
    req->send(200, "text/plain", String(val));
    //Serial.printf("web server on core: %u\n", xPortGetCoreID());    
  });

// ==================================================================
  server.on("/local_IP", HTTP_GET, [](AsyncWebServerRequest * req) {
    String return_ip;

    //Serial.print("get local_IP\n");    
    return_ip = String(local_IP[0]) + String(".") + String(local_IP[1]) + String(".") + String(local_IP[2]) + String(".") + String(local_IP[3]);     
    //Serial.print(return_ip);      
    req->send(200, "text/plain", return_ip);
  });
// ==================================================================
  server.on("/pitch", HTTP_GET, [](AsyncWebServerRequest * req) {
    int16_t val = Pitch_INT;  // 讀取光敏電阻的數值    
    //val = 99;
    //Serial.print("get pitch\n");        
    req->send(200, "text/plain", String(val));
  });  

  server.on("/roll", HTTP_GET, [](AsyncWebServerRequest * req) {
    int16_t val = Roll_INT;  // 讀取光敏電阻的數值    
    //val = 66;
    //Serial.print("get roll\n");        
    req->send(200, "text/plain", String(val));
  });  
// =================================================================

  server.on("/reaction_mode", HTTP_GET, [](AsyncWebServerRequest * req) 
  {
    //Serial.print("get reaction_mode\n");   
    if (req->hasParam("reaction_mode")) {
      AsyncWebParameter* p = req->getParam("reaction_mode");
     // parameter_val = p->value();     
      //Serial.print("get reaction_mode = " + parameter_val +"\n");        
      if (p->value() == "F") {
        // reaction_mode = FOLLOWING_MODE;
        reserved_data.reaction_mode = FOLLOWING_MODE;       
        //Serial.printf("reaction_mode = FOLLOWING_MODE\n");
      } else if (p->value() == "C") {
        // reaction_mode = COMPENSATION_MODE;
        reserved_data.reaction_mode = COMPENSATION_MODE;        
        //Serial.printf("reaction_mode = COMPENSATION_MODE\n");        
      }
    }
  });

  server.on("/reaction_mode_now", HTTP_GET, [](AsyncWebServerRequest * req) 
  {
    //Serial.print("get reaction_mode_now\n");   

    if (reaction_mode == FOLLOWING_MODE) {
      req->send(200, "text/plain", String("正向"));
      //Serial.printf("reaction_mode = FOLLOWING_MODE\n");
    } else if (reaction_mode == COMPENSATION_MODE) {
      req->send(200, "text/plain", String("反向"));
      //Serial.printf("reaction_mode = COMPENSATION_MODE\n");        
    }
    req->send(200, "text/plain", "OK!");
  });

// =================================================================
  server.on("/step", HTTP_GET, [](AsyncWebServerRequest * req) 
  {  
    int16_t val;
    //Serial.print("get step\n"); 
    if (req->hasParam("step")) {
      AsyncWebParameter* p = req->getParam("step");
      parameter_val = p->value();     
      //Serial.print("get degree_quota = " + parameter_val +"\n");        
      // step = (int16_t)parameter_val.toInt();  
      val = (int16_t)parameter_val.toInt();  
      if ((val >= 1) && (val <= 25))
      {
        reserved_data.step = (int16_t)parameter_val.toInt();  
      }
    }
  });


  server.on("/step_now", HTTP_GET, [](AsyncWebServerRequest * req) {
    //Serial.print("get step_now\n");
    int16_t val;
    
    switch (reserved_data.step)
    {
      case 1 ... 2:
        val = 1;
        break;
      case 3 ... 4:
        val = 2;
        break;    
      case 5 ... 7:
        val = 3;
        break;     
      case 8 ... 12:
        val = 4;
        break;     
      case 13 ... 25:
        val = 5;
        break;                          
    }    
  
    req->send(200, "text/plain", String(val));
    //Serial.printf("web server on core: %u\n", xPortGetCoreID());    
  });


// =================================================================
  server.on("/z_quota", HTTP_GET, [](AsyncWebServerRequest * req) {
    double val;
    //Serial.print("get z_quota\n");      
    if (req->hasParam("z_quota"))
    {
      AsyncWebParameter* p = req->getParam("z_quota");
      parameter_val = p->value();
      //Serial.print("get z_quota = " + parameter_val + "\n");     
      // z_quota = parameter_val.toDouble();
      val = parameter_val.toDouble();
      if (( val >= 0) && (val <= 200.0)) 
      {
        reserved_data.z_quota = parameter_val.toDouble();
      }

      //Serial.print("get has z_quota = %f\n", z_quota);   // can't be compiled passed, very strangy     
    }
  });  


  server.on("/z_quota_now", HTTP_GET, [](AsyncWebServerRequest * req) {
    double val = reserved_data.z_quota;   
    //uint16_t val = 99;
    //Serial.print("get z_quota_now\n");        
    req->send(200, "text/plain", String(val));
  });  


 // ==================================
  server.on("/reset_default_parameter", HTTP_GET, [](AsyncWebServerRequest * req) {
    //Serial.print("get reset_default_parameter\n");            
    reset_default_parameter();
  });  

  server.on("/save_parameter", HTTP_GET, [](AsyncWebServerRequest * req) {
    //Serial.print("get save_parameter\n");       
    save_parameter();    
  });   


   // ==================================
  server.on("/show_angle", HTTP_GET, [](AsyncWebServerRequest * req) {
    double val = rotation_quota;     
    //uint16_t val = 99;
    //Serial.print("get show_angle\n");           
    req->send(200, "text/plain", String("OK"));
  });   

     // ==================================
  server.on("/survival_time", HTTP_GET, [](AsyncWebServerRequest * req) {
    // uint32_t val = millis();  
    // //Serial.printf("survival time = %d\n", val);           
    // req->send(200, "text/plain", String(val));
    req->send(200, "text/plain", String(millis()));
  });   

  
  server.begin();
  Serial.println("HTTP server ready!");  
  yield();
}


void init_WiFi(void) {
  unsigned long start_Time;
  /* WiFi settings */
  Serial.println();
  Serial.print("Connecting to wifi: ");
  Serial.println(field_ssid);
  Serial.flush();
  WiFi.mode(WIFI_AP_STA);
  WiFi.begin(field_ssid, field_password);
  start_Time = millis();
  while (true)
  {
    if (WiFi.status() == WL_CONNECTED)
    {
        //Serial.print("Connected");
        local_IP = WiFi.localIP();    
        Serial.print("\nWIFI is connected, The local IP address is: ");      
        Serial.print(local_IP);      
        WiFi.softAPConfig(AP_local_ip, AP_gateway, AP_subnet);  // must place after WiFi.begin
        WiFi.softAP(AP_ssid, AP_password);        
        break;
    }else
    {
      if  (millis() - start_Time >= 5000)
      {
        Serial.print("\nWIFI Connect fail");     
        WiFi.mode(WIFI_AP); // should change mode, if WIFI_AP_STA fail
        WiFi.softAPConfig(AP_local_ip, AP_gateway, AP_subnet);
        WiFi.softAP(AP_ssid, AP_password);     
        // WiFi.config(IPAddress(192,168,0,100), IPAddress(192,168,0,100), IPAddress(255,255,255,0));
        // local_IP = IPAddress(192,168,0,100);
        break;
      } else
      {
        delay(500);
        Serial.print(".");
      }
    }
  }
  Serial.println();

  Serial.print("AP: 192,168,10,1, subnet mask 255,255,255,0\n");    

  if (!MDNS.begin(host)) { //http://Richard.local
    Serial.println("設置MDNS回應器時出錯了~");
    while (1) {
      delay(1000);
    }
  }

  MDNS.setInstanceName("Cubie's ESP32");  // 設置實體名稱
  MDNS.addService("http", "tcp", 80);       // 設置服務描述
  
  /* Init and get the time */
  configTime(set_gmtOffset_sec, set_daylightOffset_sec, set_ntpServer);
}
balance_platfor_2024_0613.ino
// 2024_0316: finish all basic functions

#include <Arduino.h>
#include "init.h"
#include <SPIFFS.h>
#include <Commander.h>
#include "EEPROM.h"
#include <esp_task_wdt.h>
#include "esp_system.h"

// *********************************************************************************************************************************
// *********************************************************************************************************************************
// "1.00.01";  // add version number
// "1.00.02";  // add more delay to compromize the time of platform returning to original point
//"1.00.03";  // add survival time on web page, this version seems better that not easy crash when browse it
//"1.00.04";  // change to .svg vector img file for web page icon
//"1.00.05";  // remove index.html\window.setInterval(function () to improve crash problem significantly, but not really to resolve
const char *version = "1.00.06";
// 1. screen all varible data type conversions,
// 2. check varible at each begin of loop and web change data in the structure of reserved_data rather than varible immediately
// **********************************************************************************************************************************
// **********************************************************************************************************************************


// #include <esp_cpu.h>
//Serial使用GPIO1->TX0,GPIO3->RX0,通常用於USB通訊和寫程式debug使用,預設系統使用
//Serial1: platform,使用GPIO10->TX1,GPIO9->RX1,通常用於SPI flash上,預設系統未使用
//Serial2: JY901S,使用GPIO17->TX2,GPIO16->RX2,通常用於自行使用,大部分的人都會使用這個,預設系統未使用

// pitch 16, roll 14
// #define Z_AXIS_quota_FOR_ACCELERATION  60.0
// #define Z_AXIS_quota_FOR_PITCH_ROLL   140.0

//pitch 17, roll 15
//#define Z_AXIS_quota_FOR_ACCELERATION  50.0
//#define Z_AXIS_quota_FOR_PITCH_ROLL   150.0

//static const uint8_t LED_BUILTIN = 2;
//pitch 17, roll 15
#define Z_AXIS_quota_FOR_ACCELERATION  200.0  // over use for Z-axis    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
#define Z_AXIS_quota_FOR_PITCH_ROLL    150.0
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

void playing_senarion(void);

TaskHandle_t handle_platform;
TaskHandle_t handle_webserver;
uint16_t stackSize_platform  = 3000;   // 分配給任務的記憶體大小
uint16_t stackSize_webserver = 4000;   // 分配給任務的記憶體大小5
uint32_t chipId   = 0;
uint16_t omission = 30;
int8_t   reaction_mode  = COMPENSATION_MODE; //compensation
double   rotation_quota = Z_AXIS_quota_FOR_PITCH_ROLL;
uint8_t  show_angle  = 1;
uint8_t  show_height = 0;
uint8_t  show_length = 0;
int16_t  step = 3;
// this toward_step is related to z_ratio, omission
// z_ratio  omission toward_step  deviation  comment
//   10        30         0.9      +-8~+-30    best
double   toward_step    = 0.9;
uint8_t  transmission_adjust = 1;
double   z_quota        = Z_AXIS_quota_FOR_ACCELERATION;
double   z_quota_left;
uint16_t z_ratio        = 10;  // suggest use around "10" that is significant
int16_t  degree_quota;

MyStructure reserved_data;
// UART1: balance_platform
// UART2: JY901S

//extern void init_serial(void);

uint16_t time_distance_ratio = 2;
uint16_t check_period = 50;
uint8_t  before_loop  = 1;
uint8_t  serial0_received_bytes = 0;
uint8_t  serial1_received_bytes = 0;
uint8_t  serial2_received_bytes = 0;
uint16_t execution_speed   = 50;
uint32_t step_length       = 40;  //
uint8_t  new_JY901S_packet = 0;

// read current as base number
double base_Roll_F;
double base_Pitch_F;
double base_Yaw_F;
double Injection_Pitch_F;
double Injection_Roll_F;

double v0 = 0, v = 0;
double base_az_g  = -1.002666 ; //4F = 0.995605, 18F = 0.999 ~ 1.000  //6F林口 = -0.994208
double previous_g = -1.003906;
double g_a        = 9806.65;    //9.80665 m/s², s = 1/2at^2
double delta_g_a          = 0;
double previous_delta_g_a = 0;
double add_distance = 0, z_distance = 0, previous_z_distance = 0;

double z_current = 0;
double z_upper_bound = (Z_AXIS_quota_FOR_ACCELERATION / 2);
double z_lower_bound = (-1 * Z_AXIS_quota_FOR_ACCELERATION / 2);
uint32_t loop_delay_ms = 10;

uint8_t cmd_t0_CH9121_REACTION[] = {0x55, 0xAA, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xFF, 0xFF,
                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x20, //800
                                    0x00, 0x02, 0xE3, 0x6B, 0x00, 0x02, 0xE3, 0x6B, 0x00, 0x02,   // index of:  #1 20~23 , #2 24~27 , #3 28~31
                                    0xE3, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                                   };    // 38 bytes

int32_t  Height      = 0;
int32_t  base_height = 7430;  //7430: 4F三峽; //28500: 6F林口
double   base_height_F;
uint8_t  i_Z_axis_adjust = 0;
int32_t  z_Height, z_Height_previous;

// common  variables
uint8_t *TH, *TL;
uint16_t T;
double   T_F;

// 0x5551  variables

uint8_t *axH, *axL;
uint16_t ax;
int16_t *ax_p;
double   ax_F;

uint8_t *ayH, *ayL;
uint16_t ay;
int16_t *ay_p;
double   ay_F;

uint8_t *azH, *azL;
uint16_t az;
int16_t *az_p;
double   az_F;

// 0x5552  variables

uint8_t *wxH, *wxL;
uint16_t wx;
double   wx_F;

uint8_t *wyH, *wyL;
uint16_t wy;
double   wy_F;

uint8_t *wzH, *wzL;
uint16_t wz;
double   wz_F;

// 0x5553  variables
uint8_t *RollH, *RollL;  // x axis, 滾轉角
uint16_t Roll;
double   Roll_F;
volatile int16_t  Roll_INT;

uint8_t *PitchH, *PitchL;// y axis, 俯仰角
uint16_t Pitch;
double   Pitch_F;
volatile int16_t  Pitch_INT;

uint8_t *YawH, *YawL;    // z axis, 偏航角
uint16_t Yaw;
double   Yaw_F;

// 0x5554  variables
uint8_t *HxH, *HxL;
uint16_t Hx;
double   Hx_F;

uint8_t *HyH, *HyL;
uint16_t Hy;
double   Hy_F;

uint8_t *HzH, *HzL;
uint16_t Hz;
double   Hz_F;

double move_step;
double slope_X, slope_Y;
double length_X       = 1000, length_y = 1000; //mm
double height_max     = 20;
double height_need_Z  = 0;
double height         = 0;  // +- 100mm

uint8_t action_status = 0;
double x_axis_length  = 470;
double y_axis_length  = 550;

int32_t base_length = 100;
int32_t average_length;
int32_t increasing_length;

int32_t length_1 = 100;
int32_t length_2 = 100;
int32_t length_3 = 100;
int32_t length_1_previous = 100;
int32_t length_2_previous = 100;
int32_t length_3_previous = 100;

int32_t length_1_total   = 0;
int32_t length_2_total   = 0;
int32_t length_3_total   = 0;
int32_t length_1_remain  = 0;
int32_t length_2_remain  = 0;
int32_t length_3_remain  = 0;

double pitch_limitation_positive;
double pitch_limitation_negtive;
double roll_limitation_positive;
double roll_limitation_negtive;
double pitch_plus_roll_limitation_positive;
double pitch_plus_roll_limitation_negtive;

//uint16_t max_roll = 0;

// Commander 接口构型
// - serial  - 可选择接收 HardwareSerial 或 Stream 实例
// - eol     - 可选择接收 eol 字符 - 默认另起一行: "\n"
// - echo    - 可选的 echo 行结束符(命令行反馈)  - 默认 false
//Commander commander = Commander(Serial, "\n", false);
Commander cmd;
uint16_t transmission_adjust_table[] = {1250, 1250, 1603, 1746, 1672, 1577, 1490, 1413, 1348, 1292, 1244 , 1203, 1167, 1136, 1110, 1089, 1071, 1059, 1051, 1050, 1250, 1250, 1250};
uint32_t length_value_table[] = {0, 0x30D4, 0x7D40, 0xCCB3, 0x10550, 0x1341D, 0x15D38, 0x18299, 0x1A562, 0x1C655, 0x1E5FC, 0x204C4, 0x22309, 0x24121, 0x25F63, 0x27E2F, 0x29DFC, 0x2BF6A, 0x2E36B, 0x30BAD, 0x3D0A4};
uint16_t length_1_ratio, length_2_ratio, length_3_ratio;
uint8_t  index1, index2, index3;
uint8_t *execution_speed_p;

void setup() {
  // char *sent_string;
  uint32_t Freq = 0;
  // pinMode(LED_BUILTIN, OUTPUT);
  // 8 sec(delay) + 12 sec(Http server) + 4 sec(vertical movement) + 8 sec(rotation) + 3 sec(return to original) + 5 sec(delay) == 40 sec
  delay(8000); //delay(ms)    // this wait for unstable power source to stable, don't remove this !!!
  delay(12000); // add more delay to compromize the time of platform returning original point

  // digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  // delay(500);                      // wait for a second
  // digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW

  init_serial();
  initialiseCommander();
  init_WiFi();
  Serial.print("version = ");
  Serial.println(version);
  //xTaskCreatePinnedToCore(WebServer,  "WebServer", 15000, NULL,  0, NULL, 0);
  //xTaskCreate(WebServer,  "WebServer", 2000, NULL,  0, NULL);
  //Serial.println("掛載SPIFFS分區出錯啦~");
  //Serial.flush();  // wait Serial FIFO to be empty and then spend almost no time processing it
  //Serial.flush();  // wait Serial FIFO to be empty and then spend almost no time processing it
  if (!SPIFFS.begin(true))
  {
    Serial.printf("mount SPIFFS fail\n");
    return;
  } else
  {
    Serial.printf("mount SPIFFS done\n");
  }
  init_JY901S();

  // digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  // delay(500);                      // wait for a second
  // digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  // delay(500);
  // digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  // delay(500);                      // wait for a second
  // digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW

  //calculate_angle_limitation();  //? do we need it here?
  delay(1000); //delay(ms)
  init_platform();  //lift to 100ms initially

  // digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  // delay(500);                      // wait for a second
  // digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  // delay(500);
  // digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  // delay(500);                      // wait for a second
  // digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  // delay(500);
  // digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  // delay(500);                      // wait for a second
  // digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW


  // for(int i=0; i<17; i=i+8) {
  //   chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
  // }

  // Serial.printf("ESP32 Chip model = %s Rev %d\n", ESP.getChipModel(), ESP.getChipRevision());
  // Serial.printf("This chip has %d cores\n", ESP.getChipCores());
  // Serial.print("Chip ID: "); Serial.println(chipId);
  //xTaskCreate(WebServer,  "WebServer", 2000, NULL,  0, NULL);
  // rad CPU clock, it works!!!
  Freq = getCpuFrequencyMhz();
  Serial.print("CPU Freq = ");
  Serial.print(Freq);
  Serial.println(" MHz");
  // Serial.printf("setup finished!\n"); //around 160ms for a loop

  // Serial.printf(" omission = %d, reaction_mode = %d, rotation_quota = %f, show_angle = %d, show_height = %d, show_length = %d, step = %d, toward_step = %f, transmission_adjust = %d, z_quota = %f, z_ratio = %d\n",
  // omission,
  // reaction_mode,
  // rotation_quota,
  // show_angle,
  // show_height,
  // show_length,
  // step,
  // toward_step,
  // transmission_adjust,
  // z_quota,
  // z_ratio);
  init_WebServer();
  //WebServer(NULL);
  //disableCore0WDT();
  //xTaskCreate(WebServer,  "WebServer", stackSize_platform, NULL,  1, &handle_webserver);



  // new feature /////////////
  playing_senarion();

  // digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  // delay(500);                      // wait for a second
  // digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  // delay(500);
  // digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  // delay(500);                      // wait for a second
  // digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  // delay(500);
  // digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  // delay(500);                      // wait for a second
  // digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  // delay(500);
  // digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  // delay(500);                      // wait for a second
  // digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  // delay(500);
  // digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  // delay(500);                      // wait for a second
  // digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW

  // new feature /////////////

  // iniialize data to start
  z_distance      = 0;
  length_1        = 100;
  length_2        = 100;
  length_3        = 100;
  execution_speed = 50;
  //z_Height_previous = z_Height;
  if (!EEPROM.begin(EEPROM_SIZE))
  {
    Serial.println("failed to initialise EEPROM"); delay(1000000);
  }
  EEPROM.get(0, reserved_data);

  omission            = reserved_data.omission;
  reaction_mode       = reserved_data.reaction_mode;
  rotation_quota      = reserved_data.rotation_quota;
  show_angle          = reserved_data.show_angle;
  show_height         = reserved_data.show_height;
  show_length         = reserved_data.show_length;
  step                = reserved_data.step;
  transmission_adjust = reserved_data.transmission_adjust;
  toward_step         = reserved_data.toward_step;
  z_quota             = reserved_data.z_quota;
  z_ratio             = reserved_data.z_ratio;
  degree_quota        = reserved_data.degree_quota;

  z_quota_left        = z_quota / 2;
  Serial.printf("omission = %d, reaction_mode = %d, rotation_quota = %f, show_angle = %d, show_height = %d, show_length = %d, step = %d, toward_step = %f, transmission_adjust = %d, , z_ratio = %d\n",
                omission,
                reaction_mode,
                rotation_quota,
                show_angle,
                show_height,
                show_length,
                step,
                toward_step,
                transmission_adjust,
                z_quota,
                z_ratio);
  //xTaskCreate(task_platform,  "task_platform", stackSize_platform, NULL,  1, &handle_platform);  //stack = "4000" is very important, otherwise to execute certain command will cause crash
  //xTaskCreatePinnedToCore(task_platform,  "task_platform", stackSize_platform, NULL,  1, NULL, 0);
  Serial.println( esp_get_minimum_free_heap_size());
  Serial.println( esp_get_free_heap_size());

  Serial.print("setup finished!\n");
}

// void loop()
// {
//   //Serial.printf("main program on core: %u\n", xPortGetCoreID());
//   //yield();
//   // UBaseType_t m = stackSize_webserver - uxTaskGetStackHighWaterMark(handle_webserver);
//   // Serial.printf("webserver stack %u byte\n", m);
//   vTaskDelay(1000);
// }

// void task_platform(void * pvParam ) {
void loop()
{
  uint8_t index;
  UBaseType_t m;

  omission            = reserved_data.omission;
  reaction_mode       = reserved_data.reaction_mode;
  rotation_quota      = reserved_data.rotation_quota;
  show_angle          = reserved_data.show_angle;
  show_height         = reserved_data.show_height;
  show_length         = reserved_data.show_length;
  step                = reserved_data.step;
  transmission_adjust = reserved_data.transmission_adjust;
  toward_step         = reserved_data.toward_step;
  z_quota             = reserved_data.z_quota;
  z_ratio             = reserved_data.z_ratio;
  degree_quota        = reserved_data.degree_quota;

  z_quota_left        = z_quota / 2;
  //Serial.printf("out millis = %d\n",   millis() ); //around 50ms for a loop
  //Serial.println( esp_get_minimum_free_heap_size());
  //  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

  // while(1)
  // {
  //     esp_task_wdt_reset();
  //     yield();

  // m = stackSize_platform - uxTaskGetStackHighWaterMark(handle_platform);
  // Serial.printf("task_platform stack %u byte\n", m);
  //Serial.printf("no JY901S_packet ============================= millis = %d\n",   millis() ); //around 160ms for a loop
  before_loop = 0;
  //Serial.printf("task_platform program on core: %u\n", xPortGetCoreID());
  //Serial.printf("main program priority: %u\n", uxTaskPriorityGet());
  if (new_JY901S_packet == 1)
  {
    vTaskDelay(1);
    //delay(1);
    //Serial.printf("millis = %d\n",   millis() ); //around 50ms for a loop
    new_JY901S_packet = 0;
    // put your main code here, to run repeatedly:
    //delay(loop_delay_ms);  //delay(ms)
    //delay(100);  //delay(ms)
    // delay is set a gap between command
    //Serial.printf("new_JY901S_packet ============================= millis = %d\n",   millis() ); //around 160ms for a loop

    //if (degree_quota > 0)
    //{
    calculate_angle_limitation();

    //Serial.printf("============================\n");

    // Serial.printf("Original Roll = %f\n", Roll_F);
    // Serial.printf("Original Pitch = %f\n", Pitch_F);
    // // Serial.printf(" Yaw = %f\n", Yaw_F);    // not support at platform at all
    // Serial.printf("\n");


    // read pitch
    // read roll

    // #1 axis: pitch
    // #2 axis: roll up
    // #3 axis: roll down

    // test data
    //Pitch_F = -1;
    //Roll_F  = 2;
    length_1 = 100;
    length_2 = 100;
    length_3 = 100;
    if (show_angle) {
      //Serial.printf("Raw int Roll_F = %d, base_Roll_F = %d,, Pitch_F = %d, base_Pitch_F = %d\n", (uint16_t)(Roll_F), (uint16_t)(base_Roll_F), (uint16_t)(Pitch_F), (uint16_t)(base_Pitch_F));
      //Serial.printf("Raw int Roll_F = %d, base_Roll_F = %d,, Pitch_F = %d, base_Pitch_F = %d, base_Yaw_F = %d, Yaw_F = %d\n", (int16_t)(Roll_F), (int16_t)(base_Roll_F), (int16_t)(Pitch_F), (int16_t)(base_Pitch_F), (int16_t)(base_Yaw_F), (int16_t)(Yaw_F));
    }





    // if (show_angle) {
    //   Serial.printf("Original Roll = %d, Pitch = %d\n", Roll_INT, Pitch_INT);
    // }

    normalize_angle();
    if (show_angle) {
      //Serial.printf("after normalized Roll_F = %d, base_Roll_F = %d,, Pitch_F = %d, base_Pitch_F = %d, base_Yaw_F = %d, Yaw_F = %d\n", (int16_t)(Roll_F), (int16_t)(base_Roll_F), (int16_t)(Pitch_F), (int16_t)(base_Pitch_F), (int16_t)(base_Yaw_F), (int16_t)(Yaw_F));
      //Serial.printf("after normalized Roll = %d, Pitch = %d\n", Roll_INT, Pitch_INT);
    }

    fit_angle_limitation();
    if (show_angle) {
      //Serial.printf("after fit:  Pitch = %d, Roll = %d\n",  Pitch_INT, Roll_INT);
    }

    posture_adjust();
    if (show_angle) {
      //Serial.printf("============================= millis = %d\n",   millis() ); //around 160ms for a loop
      //Serial.printf("after  posture_adjust action_status = %d, send data ==> length_1 = %d, length_2 = %d, length_3 = %d\n", action_status, length_1, length_2, length_3);
      Serial.printf("after posture_adjust:  Pitch = %d, Roll = %d, mills = %d\n",  Pitch_INT, Roll_INT, millis());
    }

    Z_axis_adjust();
    //Z_axis_height_JY901b();

    if (show_height) {
      if ( z_Height != 0 ) {
        //Serial.printf("============================= millis = %d\n",   millis() ); //around 160ms for a loop
        Serial.printf("z_Height = %d, Height = %d, base_height = %d, base_height_F = %f\n", z_Height, Height, base_height, base_height_F);
        Serial.printf("after fit:  Pitch = %d, Roll = %d\n",  Pitch_INT, Roll_INT);
      }

    }
    if (show_length) {
      Serial.printf("after  Z_axis_height_JY901b action_status = %d, send data ==> length_1 = %d, length_2 = %d, length_3 = %d\n", action_status, length_1, length_2, length_3);
      //Serial.printf(" action_status = %d, send data ==> length_1 = %x, length_2 = %x, length_3 = %x\n", action_status, length_1*1250, length_2*1250, length_3*1250);
      //Serial.printf(" action_status = %d, send data ==> length_1 = %x, length_2 = %x, length_3 = %x\n", action_status, (length_1+increasing_length)*1250, (length_2+increasing_length)*1250, (length_3+increasing_length)*1250);
    }
    step_adjust();
    //Serial.printf("after  step_adjust action_status = %d, send data ==> length_1 = %d, length_2 = %d, length_3 = %d\n", action_status, length_1, length_2, length_3);

    boundary_protection();
    //Serial.printf("after  boundary_protection action_status = %d, send data ==> length_1 = %d, length_2 = %d, length_3 = %d\n", action_status, length_1, length_2, length_3);
    // filter noise
    if (transmission_adjust == 1)
    {
      index1 = length_1 / 10;
      index2 = length_2 / 10;
      index3 = length_3 / 10;
      //Serial.printf("length_1_ratio = %d, length_2_ratio = %d, length_3_ratio = %d\n", length_1_ratio, length_2_ratio, length_3_ratio);
      length_1_ratio = transmission_adjust_table[index1];
      length_2_ratio = transmission_adjust_table[index2];
      length_3_ratio = transmission_adjust_table[index3];

      transmit(length_1 * length_1_ratio, length_2 * length_2_ratio, length_3 * length_3_ratio );
    }
    else {
      transmit(length_1 * 1250, length_2 * 1250, length_3 * 1250 );
    }

    if (show_length) {
      //Serial.printf("base_height = %d, z_Height = %d,  length_1 = %d, length_2 = %d, length_3 = %d\n",base_height, z_Height, length_1, length_2, length_3);
      //Serial.printf(" action_status = %d, send data ==> length_1 = %d, length_2 = %d, length_3 = %d\n", action_status, length_1, length_2, length_3);
      //Serial.printf(" action_status = %d, send data ==> length_1_previous = %d, length_2_previous = %d, length_3_previous = %d\n", action_status, length_1_previous, length_2_previous, length_3_previous);
    }
    //toward_to_new_base();
    length_1_previous = length_1;
    length_2_previous = length_2;
    length_3_previous = length_3;
    //  transmit((length_1+increasing_length)*1250, (length_2+increasing_length)*1250, (length_3+increasing_length)*1250 );
  }
  else
  {
    //Serial.printf("No packet *********************************************************************************************\n");
    //delay(10);
  }

  cmd.update();
  //yield();
  // esp_task_wdt_reset();
  //  }

} // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

void boundary_protection(void)
{
  if (length_1 < 0)
    length_1 = 0;
  if (length_1 >= 200)
    length_1 = 200;

  if (length_2 < 0)
    length_2 = 0;
  if (length_2 >= 200)
    length_2 = 200;

  if (length_3 < 0)
    length_3 = 0;
  if (length_3 >= 200)
    length_3 = 200;

}

void calculate_angle_limitation(void)
{

  //uint16_t x_axis_length = 470;
  //uint16_t y_axis_length = 550;

  pitch_limitation_positive = atan(rotation_quota / x_axis_length) * 180.0 / PI; // remember to use XXX.0 rather than XXX, otherwise will cause result to zero
  pitch_limitation_negtive  = atan(rotation_quota / x_axis_length) * (-1) * 180.0 / PI;

  roll_limitation_positive  = atan(rotation_quota / y_axis_length) * 180.0 / PI;
  roll_limitation_negtive   = atan(rotation_quota / y_axis_length) * (-1) * 180.0 / PI;

  // Serial.printf("pitch_limitation_positive = %f, pitch_limitation_negtive = %f\n", pitch_limitation_positive, pitch_limitation_negtive);
  // Serial.printf("roll_limitation_positive = %f, roll_limitation_negtive = %f\n", roll_limitation_positive, roll_limitation_negtive);

}



void fit_angle_limitation(void)
{
  if ((Pitch_INT > 0 ) && (Pitch_INT > (int16_t)pitch_limitation_positive))
  {
    Pitch_INT = (int16_t)pitch_limitation_positive;
  }

  if ((Pitch_INT < 0 ) && (Pitch_INT < (int16_t)pitch_limitation_negtive))
  {
    Pitch_INT = (int16_t)pitch_limitation_negtive;
  }

  if ((Roll_INT > 0 ) && (Roll_INT > (int16_t)roll_limitation_positive))
  {
    Roll_INT = (int16_t)roll_limitation_positive;
  }

  if ((Roll_INT < 0 ) && (Roll_INT < (int16_t)roll_limitation_negtive))
  {
    Roll_INT = (int16_t)roll_limitation_negtive;
  }

}

void normalize_angle(void)
{


  if ((Pitch_F > 180) && (Pitch_F <= 360)) {
    Pitch_F = Pitch_F - 360;
  }
  Pitch_INT = (uint16_t)(Pitch_F - base_Pitch_F);

  if (Roll_F < 180.0) {
    Roll_F = Roll_F + 360.0;
  }
  Roll_INT = (uint16_t)(base_Roll_F - Roll_F);

}



void posture_adjust(void)
{

  if ((Pitch_INT >= 0) && ( Roll_INT >= 0 ))// rise #1 #2  ++
  {
    if (reaction_mode ==  FOLLOWING_MODE) {
      action_status  = 1;
    } else {
      Pitch_INT = Pitch_INT * (-1);
      Roll_INT = Roll_INT * (-1);
      action_status  = 4;
    }
  } else if ((Pitch_INT >= 0) && ( Roll_INT < 0 ))// rise #1 #3  +-
  {
    //action_status  = 2;

    if (reaction_mode ==  FOLLOWING_MODE) {
      action_status  = 2;
    } else {
      Pitch_INT = Pitch_INT * (-1);
      Roll_INT = Roll_INT * (-1);
      action_status  = 3;
    }

  } else if ((Pitch_INT < 0) && ( Roll_INT >= 0 ))// rise #2 #3 -+
  {
    //action_status  = 3;
    if (reaction_mode ==  FOLLOWING_MODE) {
      action_status  = 3;
    } else {
      Pitch_INT = Pitch_INT * (-1);
      Roll_INT = Roll_INT * (-1);
      action_status  = 2;
    }

  } else if ((Pitch_INT < 0) && ( Roll_INT < 0 ))// rise #2 #3  --
  {
    //action_status  = 4;
    if (reaction_mode ==  FOLLOWING_MODE) {
      action_status  = 4;
    } else {
      Pitch_INT = Pitch_INT * (-1);
      Roll_INT = Roll_INT * (-1);
      action_status  = 1;
    }

  }

  length_1 = 0;
  length_2 = 0;
  length_3 = 0;
  increasing_length = 0;
  switch (action_status) {  // pitch is priority than roll
    case 1:
      // (#1/#3) = pitchc:\Users\Public\Desktop\Logic 2.4.14.lnk
      // x_axis_length*tan(pitch) = #1
      length_1 = x_axis_length * tan(Pitch_INT * PI / 180); //100  // 0 degree length_1 = 0
      length_2 = y_axis_length * tan(Roll_INT * PI / 180); //57
      length_1_total = length_1 + (length_2) / 2; // 128
      if (length_1_total >= length_2) {
        if (length_1_total > rotation_quota) {
          length_1_remain = rotation_quota - length_1;
          length_2 =  length_1_remain * 2;
          length_1 = rotation_quota;
        } else {
          length_1 = length_1_total;
        }
      } else {
        if (length_2 > rotation_quota) {
          length_2_remain = rotation_quota - length_2;
          length_1 = length_1_remain / 2 + length_1;
          length_2 = rotation_quota;
        } else {
          length_1 = length_1_total;
        }
      }
      //Serial.printf("in case 1: length_1 = %d, length_2 = %d, length_3 = %d\n", length_1, length_2, length_3);
      average_length = (max(length_1, length_2)) / 2;
      z_quota_left   = 100 - average_length;
      break;

    case 2:
      length_1 = x_axis_length * tan(Pitch_INT * PI / 180); // (#1/#3) = pitch
      length_3 = y_axis_length * tan(Roll_INT * PI / 180) * (-1); // (#3/#2) = roll
      length_1_total = length_1 + (length_3) / 2;
      if (length_1_total >= length_2) {
        if (length_1_total > rotation_quota) {
          length_1_remain = rotation_quota - length_1;
          length_3 = length_1_remain * 2;
          length_1 = rotation_quota;
        } else
        {
          length_1 = length_1_total;
        }
      } else {
        if (length_3 > rotation_quota) {
          length_3_remain = rotation_quota - length_3;
          length_1 = length_1_remain / 2 + length_1;
          length_2 = rotation_quota;
        } else {
          length_1 = length_1_total;
        }
      }
      //Serial.printf("in case 1: length_1 = %d, length_2 = %d, length_3 = %d\n", length_1, length_2, length_3);
      average_length = (max(length_1, length_3)) / 2;
      z_quota_left   = 100 - average_length;
      break;

    case 3:
      // (#1/#3) = pitch
      length_2 = x_axis_length * tan(Pitch_INT * PI / 180) * (-1); // 11 : 91
      length_3 = length_2;
      length_2_total = y_axis_length * tan(Roll_INT * PI / 180) + length_3; // 7: 68
      if (length_2_total > rotation_quota) {
        length_2 = rotation_quota;
      } else {
        length_2 = length_2_total;
      }
      length_1 = (length_2 -  length_3) / 2;   // 68/2 = 34   (34,91,160)
      average_length = (length_2 + min(length_1, length_3)) / 2;
      z_quota_left   = 100 - average_length;
      break;

    case 4:
      // (#1/#2) = pitch
      length_2 = x_axis_length * tan(Pitch_INT * PI / 180) * (-1);
      length_3 = length_2;
      length_3_total = y_axis_length * tan(Roll_INT * PI / 180) * (-1) +  length_2;
      if (length_3_total > rotation_quota) {
        length_3 = rotation_quota;
      } else {
        length_3 = length_3_total;
      }
      length_1 = (length_3 - length_2) / 2;
      average_length = (length_3 + min(length_1, length_2)) / 2;
      z_quota_left   = 100 - average_length;
      break;
  }
  increasing_length = base_length - average_length;  // move object to central point
  //  Serial.printf("in case %d: shift_length_1 = %d, shift_length_2 = %d, shift_length_3 = %d\n", action_status, length_1 + increasing_length, length_2 + increasing_length, length_3 + increasing_length );
  //Serial.printf("average_length = %d, z_quota_left = %f\n", average_length, z_quota_left);
  // Serial.printf("after posture_adjust: length_1 = %d, length_2 = %d, length_3 = %d\n", length_1, length_2, length_3);


  /*
    // stepping
    if (length_1 > step_length)
    {
    length_1 = step_length;
    }
    if (length_2 > step_length)
    {
    length_2 = step_length;
    }
    if (length_3 > step_length)
    {
    length_3 = step_length;
    }
    Serial.printf(" after stepping = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", action_status, length_1, length_2, length_3);
  */


  //Serial.printf(" action_status = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", action_status, length_1, length_2, length_3);
  //Serial.printf(" in case %d: shift_length_1 = %d, shift_length_2 = %d, shift_length_3 = %d\n", action_status, length_1 + increasing_length, length_2 + increasing_length, length_3 + increasing_length );
  length_1 += increasing_length;
  length_2 += increasing_length;
  length_3 += increasing_length;

}

void step_adjust(void)
{
  // change length , but not change angle
  // up limitation
  if ((length_1 - length_1_previous) > step)
  {
    length_1 = length_1_previous + step;
  }
  if ((length_2 - length_2_previous) > step)
  {
    length_2 = length_2_previous + step;
  }
  if ((length_3 - length_3_previous) > step)
  {
    length_3 = length_3_previous + step;
  }

  // down limitation
  if ((length_1_previous - length_1) > step)
  {
    length_1 = length_1_previous - step;
  }
  if ((length_2_previous - length_2) > step)
  {
    length_2 = length_2_previous - step;
  }
  if ((length_3_previous - length_3) > step)
  {
    length_3 = length_3_previous - step;
  }

}

void toward_to_new_base(void)
{
  if (z_Height > 0)
  {
    base_height_F += toward_step;
    base_height = (uint32_t)base_height_F;
    //Serial.printf("toward_to_new_base+\n");
  }
  if (z_Height < 0)
  {
    base_height_F -= toward_step;
    base_height = (uint32_t)base_height_F;
    //Serial.printf("toward_to_new_base-\n");
  }
}

void transmit(uint32_t length_1, uint32_t length_2, uint32_t length_3 )
{
  /*
    uint8_t cmd_t0_CH9121_REACTION[] = {0x55, 0xAA, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xFF, 0xFF,
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x20,
                            0x00, 0x02, 0xE3, 0x6B, 0x00, 0x02, 0xE3, 0x6B, 0x00, 0x02,   // index of:  #1 20~23 , #2 24~27 , #3 28~31
                            0xE3, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};    // 38 bytes
  */
  uint8_t *length_1p,  *length_2p,  *length_3p;
  uint8_t *temp_p;
  uint8_t i;
  uint8_t sent_bytes;


  execution_speed_p = &(cmd_t0_CH9121_REACTION[18]);

  length_1p = &(cmd_t0_CH9121_REACTION[20]);
  length_2p = &(cmd_t0_CH9121_REACTION[24]);
  length_3p = &(cmd_t0_CH9121_REACTION[28]);

  *execution_speed_p      = execution_speed / 256;
  *(execution_speed_p + 1)  = execution_speed % 256;

  /*  test data
    length_1 = 0x01020304;
    length_2 = 0x01020304;
    length_3 = 0x01020304;
  */

  // little endian to big endian
  temp_p = (uint8_t *)&length_1;
  *(length_1p + 0) = *(temp_p + 3);
  *(length_1p + 1) = *(temp_p + 2);
  *(length_1p + 2) = *(temp_p + 1);
  *(length_1p + 3) = *(temp_p + 0);

  temp_p = (uint8_t *)&length_2;
  *(length_2p + 0) = *(temp_p + 3);
  *(length_2p + 1) = *(temp_p + 2);
  *(length_2p + 2) = *(temp_p + 1);
  *(length_2p + 3) = *(temp_p + 0);

  temp_p = (uint8_t *)&length_3;
  *(length_3p + 0) = *(temp_p + 3);
  *(length_3p + 1) = *(temp_p + 2);
  *(length_3p + 2) = *(temp_p + 1);
  *(length_3p + 3) = *(temp_p + 0);

  /*
    Serial.printf("\n new data: ");
    for (i = 0; i < 38; i++ )
    {
      Serial.printf("%x", cmd_t0_CH9121_REACTION[i]);  // fill it with characters A..Z
      if (i < 37)
      {
        Serial.printf("-");  // fill it with characters A..Z
      }
      else {
        Serial.printf("\n");
      }
    }
  */

  sent_bytes = Serial1.write(cmd_t0_CH9121_REACTION, sizeof(cmd_t0_CH9121_REACTION));  // ESP32 TX FIFO is about 128 bytes, 125 bytes will fit fine
  //bytesSent = Serial1.write(cmd_t0_CH9121_Up, sizeof(cmd_t0_CH9121_Up));

}


void Z_axis_adjust(void)
{
  // double base_az_F  = 0.995605;
  // double g          = 9806.65;    //9.80665 m/s², s = 1/2at^2
  // double delta_g    = 0;
  double vertical_a = 0;
  double one_step_limitaion = 1000;
  double ratio = z_ratio;
  double t = 0.05;  // 50ms, // don't fast than this rate, CPU can't afford to more than 50Hz/20ms

  double z_max, z_min, z_tmp_max, z_tmp_min;
  double real_add;
  int32_t direction; //up down direction
  //Serial.printf("Height = %d, base_height = %d, ax_F = %f, ay_F = %f, az_F = %f, Pitch_F = %f, Roll_F = %f\n", Height, base_height,  ax_F, ay_F, az_F, Pitch_F, Roll_F);

  if ((Height - base_height) > 0)
  {
    direction = 1;
  } else if ((Height - base_height) < 0)
  {
    direction = -1;
  } else
  {
    direction = 0;
  }
  z_upper_bound = (z_quota / 2);
  z_lower_bound = (-1 * z_quota / 2);

  vertical_a    = az_F * cos((Pitch_F) * TWO_PI / 360.0) * cos((Roll_F) * TWO_PI / 360.0) - ax_F * sin((Pitch_F) * TWO_PI / 360.0) + ay_F * sin((Roll_F) * TWO_PI / 360.0);
  //Serial.printf("vertical_a = %f, ax_F = %f, ay_F = %f, az_F = %f, Pitch_F = %f, Roll_F = %f\n", vertical_a, ax_F, ay_F, az_F, Pitch_F, Roll_F);
  //Serial.printf("direction = %d\n", direction);
  //Serial.printf("az_F = %f\n", az_F);
  delta_g_a = 1 * (vertical_a - base_az_g) * g_a;
  //Serial.printf("vertical_a = %f, delta_g_a = %f\n", vertical_a, delta_g_a);
  if ( abs(delta_g_a) >= omission ) // eliminate noise: like as gap of Gravity difference, small motion, ...
  { // 50: 9880*0.005
    //Serial.printf("delta_g_a = %f\n", delta_g_a);
    //Serial.printf("v0 = %f\n", v0);
    //if ((delta_g_a * previous_delta_g_a < 0 ) && ( abs(delta_g_a - previous_delta_g_a) > 8000.0)) {
    /*
      if (delta_g_a * previous_delta_g_a < 0 ) {
        v  = 0;
        v0 = 0;
        Serial.printf("reset v0\n");
      }
      else
    */
    {
      v = v0 + delta_g_a * t;
      //z_distance = z_distance + v0*t +  0.5*delta_g_a*t*t;
      z_distance = v0 * t +  0.5 * delta_g_a * t * t; //t : each loop cycle time
      v0 = v;
    }
    //z_distance = z_distance + velocity*0.02*ratio;  //0.02 : each loop cycle time

    previous_delta_g_a  = delta_g_a;
    //Serial.printf("v0 = %f\n", v0);
    //Serial.printf("z_distance = %f, previous_z_distance = %f\n", z_distance, previous_z_distance);
    //Serial.printf("z_distance = %f, millis = %d\n", z_distance, millis() );
    if (abs(previous_z_distance - z_distance) >= 100)  {
      z_distance = (previous_z_distance - z_distance) / 2;
    }


    //Serial.printf("add_distance = %f, millis = %d\n", add_distance, millis() );


    // length_1 =  100 + add_distance;
    // length_2 =  100 + add_distance;
    // length_3 =  100 + add_distance;

    // if (add_distance > 0){
    //   real_add = min(z_upper_bound, add_distance);
    // } else {
    //   real_add = max(z_lower_bound, add_distance);
    // }
    //Serial.printf("z_upper_bound = %f, z_lower_bound = %f, add_distance = %f, real_add = %f\n", z_upper_bound, z_lower_bound, add_distance, real_add);
    //Serial.printf("direction = %d, z_distance = %f, previous_z_distance = %f\n", direction, z_distance, previous_z_distance);
    if (direction = 1)  //same direction, that is effective force
      //if (direction != 0)  //same direction, that is effective force
    {
      //add_distance = -1 * z_distance;
      //add_distance = z_distance*ratio;
      z_Height = (int32_t)(z_distance * ratio);
      if (z_Height > z_quota_left )
      {
        z_Height = z_quota_left;
      }

      if (z_Height < (-1 * z_quota_left))
      {
        z_Height = -1 * z_quota_left;
      }
      //Serial.printf("consistancy z_Height = %d\n", z_Height );
      //Serial.printf("direction = %d, z_Height = %d\n", direction, z_Height);
      if (reaction_mode ==  FOLLOWING_MODE) {
        length_1 += z_Height;
        length_2 += z_Height;
        length_3 += z_Height;
      } else {
        length_1 -= z_Height;
        length_2 -= z_Height;
        length_3 -= z_Height;
      }
    }
    else
    {
      z_distance = previous_z_distance;
      //Serial.printf("direction = %d, z_Height = %d\n", direction, z_Height );
    }
    previous_z_distance = z_distance;

    /*
      i_Z_axis_adjust++;

      if ((i_Z_axis_adjust%10)==0 )
      {
      //Serial.printf("add_distance = %f\n", add_distance );
      Serial.printf("z_Height = %d\n", z_Height );
      }
    */

    //Serial.printf(" action_status = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", action_status, length_1, length_2, length_3);
    //Serial.printf(" in case %d: shift_length_1 = %d, shift_length_2 = %d, shift_length_3 = %d\n", action_status, length_1 + increasing_length, length_2 + increasing_length, length_3 + increasing_length );
  }
  else {
    v0 = 0;
  }
}

void Z_axis_height_JY901b(void)
{
  z_Height = Height - base_height;
  if (z_Height != 0)
  {
    toward_to_new_base();
  }
  if (z_Height >= z_quota_left)
  {
    z_Height = z_quota_left;
  }

  if (z_Height <= (-1 * z_quota_left))
  {
    z_Height = -1 * z_quota_left;
  }

  //Serial.printf("z_Height = %d, z_Height_previous = %d\n",z_Height, z_Height_previous);
  //Serial.printf("z_Height = %d, Pitch_INT = %d, Roll_INT = %d\n",z_Height, Pitch_INT, Roll_INT);
  // if ((abs(z_Height_previous - z_Height) <= z_ratio+1) && (z_Height_previous == 0)) //try to filter noise
  // {
  //   z_Height_previous = z_Height;
  //   z_Height = 0;
  //   Serial.printf("in z_Height = %d\n",z_Height);
  // }

  if (abs(z_Height) <= (omission)) //try to filter noise
    //if (((abs(Pitch_INT) <= 0 ) && (abs(Roll_INT) <= 0))) //try to filter noise
    //if ((Pitch_INT == 0 ) && (Roll_INT == 0)) //try to filter noise
    //if (abs(z_Height) <= (omission) ) //try to filter noise
  {
    z_Height_previous = z_Height;
    z_Height = 0;
    //Serial.printf("inner z_Height = %d\n",z_Height);
  }
  else
  {
    //Serial.printf("move z_Height = %d\n",z_Height);
    z_Height_previous = z_Height;
    if (reaction_mode ==  FOLLOWING_MODE) {
      length_1 += z_Height;
      length_2 += z_Height;
      length_3 += z_Height;
    } else {
      length_1 -= z_Height;
      length_2 -= z_Height;
      length_3 -= z_Height;
    }
  }
  //Serial.printf(" action_status = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", action_status, length_1, length_2, length_3);
  //Serial.printf("z_Height = %d,  length_1 = %d, length_2 = %d, length_3 = %d\n",z_Height, length_1, length_2, length_3);
  //Serial.printf("z_Height = %d\n",z_Height);
  //z_Height_previous = z_Height;

}

void playing_senarion(void)
{
  int kk;

  omission            = 30;
  reaction_mode       = FOLLOWING_MODE;
  rotation_quota      = 150;
  step                = 3;
  transmission_adjust = 1;
  toward_step         = 1;
  z_quota             = 200;
  z_ratio             = 15;
  degree_quota        = 15;
  z_quota_left        = z_quota / 2;
  // up to 200
  // return to center
  // roll to 15 step 5
  // roll to -15 step 5
  // pitch to 17 step 5
  // pitch down -15 step 5
  // run in sin wave a clcle

  uint16_t delay_control = 800;

  // Injection_Pitch_F = base_Pitch_F;
  // Injection_Roll_F  = base_Roll_F;
  delay(1000);
  // Pitch_F = base_Pitch_F;
  // Pitch_F = base_Pitch_F;

  // transmit(length_1*1250, length_2*1250, length_3*1250 );
  execution_speed = delay_control + 1000;
  transmit(length_value_table[20], length_value_table[20], length_value_table[20] );
  // Serial.printf("cmd_t0_CH9121_Up200mm\n");
  // for (kk = 0; kk < 38; kk++)
  // {
  //   Serial.printf(" %x ", cmd_t0_CH9121_REACTION[kk]);
  // }
  // execution_speed_p = &(cmd_t0_CH9121_Up200mm[18]);
  // *execution_speed_p      = execution_speed / 256;
  // *(execution_speed_p+1)  = execution_speed % 256;
  // Serial1.write(cmd_t0_CH9121_Up200mm, 38);
  delay(delay_control);

  execution_speed = delay_control;
  transmit(length_value_table[0], length_value_table[0], length_value_table[0] );
  // Serial.printf("cmd_t0_CH9121_Original\n");
  // for (kk = 0; kk < 38; kk++)
  // {
  //   Serial.printf(" %x ", cmd_t0_CH9121_REACTION[kk]);
  // }

  // execution_speed_p = &(cmd_t0_CH9121_Original[18]);
  // *execution_speed_p      = execution_speed / 256;
  // *(execution_speed_p+1)  = execution_speed % 256;
  // Serial1.write(cmd_t0_CH9121_Original, 38);
  delay(delay_control);

  transmit(length_value_table[10], length_value_table[10], length_value_table[10] ); // 10 cm
  // Serial.printf("cmd_to_100mm\n");
  // for (kk = 0; kk < 38; kk++)
  // {
  //   Serial.printf(" %x ", cmd_t0_CH9121_REACTION[kk]);
  // }
  // execution_speed_p = &(cmd_t0_CH9121_Up100mm[18]);
  // *execution_speed_p      = execution_speed / 256;
  // *(execution_speed_p+1)  = execution_speed % 256;
  // Serial1.write(cmd_t0_CH9121_Up100mm, 38);
  delay(delay_control);

  Pitch_INT = 15;
  Roll_INT  = 0;
  // Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  //Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1_previous = %d, length_2_previous = %d, length_3_previous = %d\n", Pitch_INT, Roll_INT, length_1_previous, length_2_previous, length_3_previous );
  dancing_show();
  //Serial.printf("pitch_limitation_positive = %f, pitch_limitation_negtive = %f, roll_limitation_positive = %f, roll_limitation_negtive = %f\n",  pitch_limitation_positive, pitch_limitation_negtive, roll_limitation_positive, roll_limitation_negtive  );
  delay(delay_control);

  Pitch_INT =  10;
  Roll_INT  = -10;
  // Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  //Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1_previous = %d, length_2_previous = %d, length_3_previous = %d\n", Pitch_INT, Roll_INT, length_1_previous, length_2_previous, length_3_previous );
  dancing_show();
  //Serial.printf("pitch_limitation_positive = %f, pitch_limitation_negtive = %f, roll_limitation_positive = %f, roll_limitation_negtive = %f\n",  pitch_limitation_positive, pitch_limitation_negtive, roll_limitation_positive, roll_limitation_negtive  );
  delay(delay_control);

  Pitch_INT =   0;
  Roll_INT  = -15;
  // Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  //Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1_previous = %d, length_2_previous = %d, length_3_previous = %d\n", Pitch_INT, Roll_INT, length_1_previous, length_2_previous, length_3_previous );
  dancing_show();
  //Serial.printf("pitch_limitation_positive = %f, pitch_limitation_negtive = %f, roll_limitation_positive = %f, roll_limitation_negtive = %f\n",  pitch_limitation_positive, pitch_limitation_negtive, roll_limitation_positive, roll_limitation_negtive  );
  delay(delay_control);

  Pitch_INT = -10;
  Roll_INT  = -10;
  // Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  //Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1_previous = %d, length_2_previous = %d, length_3_previous = %d\n", Pitch_INT, Roll_INT, length_1_previous, length_2_previous, length_3_previous );
  dancing_show();
  //Serial.printf("pitch_limitation_positive = %f, pitch_limitation_negtive = %f, roll_limitation_positive = %f, roll_limitation_negtive = %f\n",  pitch_limitation_positive, pitch_limitation_negtive, roll_limitation_positive, roll_limitation_negtive  );
  delay(delay_control);

  Pitch_INT = -15;
  Roll_INT  =   0;
  // Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  //Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1_previous = %d, length_2_previous = %d, length_3_previous = %d\n", Pitch_INT, Roll_INT, length_1_previous, length_2_previous, length_3_previous );
  dancing_show();
  delay(delay_control);

  Pitch_INT = -10;
  Roll_INT  =  10;
  // Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  dancing_show();
  delay(delay_control);

  Pitch_INT =  0;
  Roll_INT  = 15;
  // Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  dancing_show();
  delay(delay_control);

  Pitch_INT = 10;
  Roll_INT  = 10;
  // Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  //Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1_previous = %d, length_2_previous = %d, length_3_previous = %d\n", Pitch_INT, Roll_INT, length_1_previous, length_2_previous, length_3_previous );
  dancing_show();
  delay(delay_control);

  Pitch_INT = 15;
  Roll_INT  =  0;
  // Serial.printf("Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  dancing_show();
  delay(delay_control);

  execution_speed_p = &(cmd_t0_CH9121_Up100mm[18]);
  *execution_speed_p      = execution_speed / 256;
  *(execution_speed_p + 1)  = execution_speed % 256;
  Serial1.write(cmd_t0_CH9121_Up100mm, 38);
  delay(delay_control);

  int ii;
  execution_speed = 50;
  // for (ii = 0; ii < 3; ii++ )
  // {

  transmit(length_value_table[20], length_value_table[20], length_value_table[20] ); // 10 cm
  Serial.printf("cmd_t0_CH9121_Up200mm\n");
  // for (kk = 0; kk < 38; kk++)
  // {
  //   Serial.printf(" %x ", cmd_t0_CH9121_REACTION[kk]);
  // }
  // execution_speed_p = &(cmd_t0_CH9121_Up200mm[18]);
  // *execution_speed_p      = execution_speed / 256;
  // *(execution_speed_p+1)  = execution_speed % 256;
  // Serial1.write(cmd_t0_CH9121_Up200mm, 38);
  delay(1000);

  transmit(length_value_table[10], length_value_table[10], length_value_table[10] ); // 10 cm
  Serial.printf("cmd_t0_CH9121_Up100mm\n");
  // for (kk = 0; kk < 38; kk++)
  // {
  //   Serial.printf(" %x ", cmd_t0_CH9121_REACTION[kk]);
  // }
  // execution_speed_p = &(cmd_t0_CH9121_Up100mm[18]);
  // *execution_speed_p      = execution_speed / 256;
  // *(execution_speed_p+1)  = execution_speed % 256;
  // Serial1.write(cmd_t0_CH9121_Up100mm, 38);
  delay(1000);

  transmit(length_value_table[17], length_value_table[17], length_value_table[17] ); // 10 cm
  Serial.printf("cmd_t0_CH9121_Up170mm\n");
  // for (kk = 0; kk < 38; kk++)
  // {
  //   Serial.printf(" %x ", cmd_t0_CH9121_REACTION[kk]);
  // }
  // execution_speed_p = &(cmd_t0_CH9121_Up170mm[18]);
  // *execution_speed_p      = execution_speed / 256;
  // *(execution_speed_p+1)  = execution_speed % 256;
  // Serial1.write(cmd_t0_CH9121_Up170mm, 38);
  delay(1000);

  transmit(length_value_table[10], length_value_table[10], length_value_table[10] ); // 10 cm
  Serial.printf("cmd_t0_CH9121_Up100mm\n");
  // for (kk = 0; kk < 38; kk++)
  // {
  //   Serial.printf(" %x ", cmd_t0_CH9121_REACTION[kk]);
  // }
  // execution_speed_p = &(cmd_t0_CH9121_Up100mm[18]);
  // *execution_speed_p      = execution_speed / 256;
  // *(execution_speed_p+1)  = execution_speed % 256;
  // Serial1.write(cmd_t0_CH9121_Up100mm, 38);
  delay(1000);

  transmit(length_value_table[13], length_value_table[13], length_value_table[13] ); // 10 cm
  Serial.printf("cmd_t0_CH9121_Up130mm\n");
  // for (kk = 0; kk < 38; kk++)
  // {
  //   Serial.printf(" %x ", cmd_t0_CH9121_REACTION[kk]);
  // }
  // execution_speed_p = &(cmd_t0_CH9121_Up130mm[18]);
  // *execution_speed_p      = execution_speed / 256;
  // *(execution_speed_p+1)  = execution_speed % 256;
  // Serial1.write(cmd_t0_CH9121_Up130mm, 38);
  delay(1000);

  transmit(length_value_table[10], length_value_table[10], length_value_table[10] ); // 10 cm
  Serial.printf("cmd_t0_CH9121_Up100mm\n");
  // for (kk = 0; kk < 38; kk++)
  // {
  //   Serial.printf(" %x ", cmd_t0_CH9121_REACTION[kk]);
  // }
  // execution_speed_p = &(cmd_t0_CH9121_Up100mm[18]);
  // *execution_speed_p      = execution_speed / 256;
  // *(execution_speed_p+1)  = execution_speed % 256;
  // Serial1.write(cmd_t0_CH9121_Up100mm, 38);
  delay(1000);
  // }

  //////////////////////////////////
  execution_speed = 1000;
  transmit(length_value_table[10], length_value_table[10], length_value_table[10] ); // 10 cm
  Serial.printf("cmd_t0_CH9121_Up100mm\n");
  // execution_speed_p = &(cmd_t0_CH9121_Up100mm[18]);
  // *execution_speed_p      = execution_speed / 256;
  // *(execution_speed_p+1)  = execution_speed % 256;
  Serial1.write(cmd_t0_CH9121_Up100mm, 38);
  Serial.printf("cmd_t0_CH9121_Up100mm\n");
  delay(1000);

  Pitch_INT = 0;
  Roll_INT  = 0;
  length_1_previous = 100;
  length_2_previous = 100;
  length_3_previous = 100;
  Serial.printf("leave playing_senarion\n");
  delay(2000);

}

void dancing_show(void) {

  calculate_angle_limitation();
  length_1 = 100;
  length_2 = 100;
  length_3 = 100;
  // normalize_angle();
  //Serial.printf("pitch_limitation_positive = %f, pitch_limitation_negtive = %f, roll_limitation_positive = %f, roll_limitation_negtive = %f\n",  pitch_limitation_positive, pitch_limitation_negtive, roll_limitation_positive, roll_limitation_negtive  );
  //fit_angle_limitation();
  Serial.printf("dancing_show fit_angle_limitation Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  posture_adjust();
  // Serial.printf("dancing_show posture_adjust Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  // Z_axis_adjust();
  //step_adjust();
  //Serial.printf("dancing_show step_adjust Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  boundary_protection();
  //Serial.printf("dancing_show boundary_protection Pitch_INT = %d: Roll_INT = %d, length_1 = %d, length_2 = %d, length_3 = %d\n", Pitch_INT, Roll_INT, length_1, length_2, length_3 );
  if (transmission_adjust == 1)
  {
    index1 = length_1 / 10;
    index2 = length_2 / 10;
    index3 = length_3 / 10;
    //Serial.printf("length_1_ratio = %d, length_2_ratio = %d, length_3_ratio = %d\n", length_1_ratio, length_2_ratio, length_3_ratio);
    length_1_ratio = transmission_adjust_table[index1];
    length_2_ratio = transmission_adjust_table[index2];
    length_3_ratio = transmission_adjust_table[index3];

    transmit(length_1 * length_1_ratio, length_2 * length_2_ratio, length_3 * length_3_ratio );
  }
  else {
    transmit(length_1 * 1250, length_2 * 1250, length_3 * 1250 );
  }
  length_1_previous = length_1;
  length_2_previous = length_2;
  length_3_previous = length_3;
}
jy901s.cpp
#include <Arduino.h>
#include "init.h"

void onReceiveUart2_from_JY901S(void) 
{
  uint8_t  index;
  uint8_t *function_id_p;
  uint16_t function_id;  

  uint8_t  serial2_left_bytes; 
  uint8_t *command_p, checksum;
  //Serial.printf(">>>>>>>>>>>>>>>>>>>>>>>>>\n");      
  //Serial.printf("millis = %d\n",   millis() ); //around 160ms for a loop    
  // This is a callback function that will be activated on UART RX events
  size_t available = Serial2.available();
  serial2_received_bytes  = available;
  //Serial.printf("onReceive Callback:: There are %d bytes available: ", available);
  index = 0;
  while (available--) {
    UART2_received[index] = (uint8_t)Serial2.read();
    index++;
  }
  
  // for (uint8_t i = 0; i < serial2_received_bytes; i++) 
  // {
  //   Serial.printf("%x", UART2_received[i]);  // fill it with characters A..Z
  //   if (i < serial2_received_bytes - 1) 
  //   {
  //     Serial.printf("-");  // fill it with characters A..Z
  //   }
  // }
  // Serial.printf(" Serial2\n");  
  serial2_left_bytes = serial2_received_bytes;
  command_p = &UART2_received[0];


  while (serial2_left_bytes >= COMMAND_SEGMENT_LENGTH) 
  {
    checksum = 0;
    function_id_p = command_p;
    for (uint8_t i = 0; i < COMMAND_SEGMENT_LENGTH-1; i++) 
    {
      checksum += *(command_p+i);
    }
    if (checksum != *(command_p+COMMAND_SEGMENT_LENGTH-1))
    {
      return;
    }
    //Serial.printf(" function_id = %08x\n", *function_id_p); //don't print this line for 0x55
    //Serial.printf(" function_id = %08x\n", *(function_id_p+1));    
    function_id = (*function_id_p<<8) + *(function_id_p+1);    
  //  ax          = (*ax_p<<8) + *(ax_p+1);
  //  ay          = (*ay_p<<8) + *(ay_p+1);
  //  az          = (*az_p<<8) + *(az_p+1);
      
  // Serial.printf(" function_id = %08x\n", function_id); 
  //  Serial.printf(" ax = %08x\n", ax);   
  //  Serial.printf(" ay = %08x\n", ay); 
  //  Serial.printf(" az = %08x\n", az); 
  
    switch (function_id) 
    {

      case 0x5551:     
        //ax=((AxH<<8)|AxL)/32768*16g(g 为重力加速度,可取 9.8m/s^2)
        //ay=((AyH<<8)|AyL)/32768*16g(g 为重力加速度,可取 9.8m/s^2)
        //az=((AzH<<8)|AzL)/32768*16g(g 为重力加速度,可取 9.8m/s^2)

        axL   = command_p+2;        
        axH   = command_p+3;           
        ax    = ((uint16_t)(*axH<<8)|(uint16_t)*axL);     
        //Serial.printf(" ax = %d\n", ax);             
        ax_p = (int16_t*)&ax;
        //Serial.printf(" *ax_p = %d\n", *ax_p);          
        ax_F  = ((*ax_p)/32768.0f)*16.0f;  
        //Serial.printf(" ax_F = %f\n", ax_F);  
        
        ayL   = command_p+4;        
        ayH   = command_p+5;           
        ay    = (uint16_t)(*ayH<<8)|(uint16_t)*ayL;    
        //Serial.printf(" ay = %d\n", ay);             
        ay_p = (int16_t*)&ay;
        //Serial.printf(" *ay_p = %d\n", *ay_p);          
        ay_F  = ((*ay_p)/32768.0f)*16.0f;  
        //Serial.printf(" ay_F = %f\n", ay_F);  
        
        azL   = command_p+6;        
        azH   = command_p+7;           
        az    = (uint16_t)(*azH<<8)|(uint16_t)*azL;        
        //Serial.printf(" az = %d\n", az);             
        az_p = (int16_t*)&az;
        //Serial.printf(" *az_p = %d\n", *az_p);          
        az_F  = ((*az_p)/32768.0f)*16.0f;  
        //Serial.printf(" az_F = %f\n", az_F);    

        TL   = command_p+8;        
        TH   = command_p+9;           
        T    = (uint16_t)(*TH<<8)|(uint16_t)*TL;        
        T_F  = T/100.0f;   
        //Serial.printf(" T = %f\n", T_F);      
        break;    
          
      case 0x5552:     
        //wx=((wxH<<8)|wxL)/32768*2000(°/s)
        //wy=((wyH<<8)|wyL)/32768*2000(°/s)
        //wz=((wzH<<8)|wzL)/32768*2000(°/s)
        wxL   = command_p+2;        
        wxH   = command_p+3;           
        wx    = (uint16_t)(*wxH<<8)|(uint16_t)*wxL;        
        wx_F  = (wx/32768.0f)*2000.0f;  
        //Serial.printf(" wxL = %d\n", *wxL);  
        //Serial.printf(" wxH = %d\n", *wxH);       
        //Serial.printf(" wx = %d\n", wx);           
        //Serial.printf(" wx = %f\n", wx_F);    
        
        wyL   = command_p+4;        
        wyH   = command_p+5;           
        wy    = (uint16_t)(*wyH<<8)|(uint16_t)*wyL;        
        wy_F  = (wy/32768.0f)*2000.0f;  
        //Serial.printf(" wy = %f\n", wy_F);  
        
        wzL   = command_p+6;        
        wzH   = command_p+7;           
        wz    = (uint16_t)(*wzH<<8)|(uint16_t)*wzL;        
        wz_F  = (wz/32768.0f)*2000.0f;   
        //Serial.printf(" wz = %f\n", wz_F);     

        TL   = command_p+8;        
        TH   = command_p+9;           
        T    = (uint16_t)(*TH<<8)|(uint16_t)*TL;        
        T_F  = T/100.0f;   
        //Serial.printf(" T = %f\n", T_F);      
        break;     
  
      case 0x5553:     
      //     uint16_t usCRC16, usTemp, i, usData[4];


      // usData[0] = ((uint16_t)s_ucWitDataBuff[3] << 8) | (uint16_t)s_ucWitDataBuff[2];
      // fAcc[i] = sReg[AX+i] / 32768.0f * 16.0f;
      // fGyro[i] = sReg[GX+i] / 32768.0f * wz.0f;
      // fAngle[i] = sReg[Roll+i] / 32768.0f * 180.0f;
      // 滾轉角(x 軸)Roll=((RollH<<8)|RollL)/32768*180(°)
      // 俯仰角(y 轴)Pitch=((PitchH<<8)|PitchL)/32768*180(°)
      // 偏航角(z 轴)Yaw=((YawH<<8)|YawL)/32768*180(°)
      // 温度计算公式:T=((TH<<8)|TL) /100 ℃
      // 校验和:Sum=0x55+0x53+RollH+RollL+PitchH+PitchL+YawH+YawL+TH+TL
        RollL   = command_p+2;        
        RollH   = command_p+3;           
        Roll    = (uint16_t)(*RollH<<8)|(uint16_t)*RollL;        
        Roll_F  = (Roll/32768.0f)*180.0f;  
        //Serial.printf(" RollL = %d\n", *RollL);  
        //Serial.printf(" RollH = %d\n", *RollH);       
        //Serial.printf(" Roll = %d\n", Roll);           
        //Serial.printf(" Roll = %f\n", Roll_F);    
        
        PitchL   = command_p+4;        
        PitchH   = command_p+5;           
        Pitch    = (uint16_t)(*PitchH<<8)|(uint16_t)*PitchL;        
        Pitch_F  = (Pitch/32768.0f)*180.0f;  
        
        //Serial.printf(" Pitch = %f\n", Pitch_F);  
        
        // YawL   = command_p+6;         
        // YawH   = command_p+7;           
        // Yaw    = (uint16_t)(*YawH<<8)|(uint16_t)*YawL;        
        // Yaw_F  = (Yaw/32768.0f)*180.0f;   
        if (before_loop == 1)
        {
          base_Pitch_F = Pitch_F; 
          if ((base_Pitch_F > 180.0) && (base_Pitch_F <= 360.0)) {
            base_Pitch_F = base_Pitch_F - 360.0; 
          }     
                    
          base_Roll_F  = Roll_F;    
          // if ((base_Roll_F > 180.0) && (base_Roll_F <= 360.0)) {
          //   base_Roll_F = base_Roll_F - 360.0; 
          // }          
          if (base_Roll_F < 180.0) {
            base_Roll_F = base_Roll_F + 360.0; 
          }              
          normalize_angle();              
          // base_Yaw_F   = Yaw_F;      
          //vertical_a = az_F * cos((360.0-Pitch_F)*TWO_PI/360.0)* cos((Roll_F-180.0)*TWO_PI/360.0) - ax_F * sin((360.0-Pitch_F)*TWO_PI/360.0) + ay_F * sin((Roll_F-180.0)*TWO_PI/360.0);           
          //base_az_g    = az_F * cos((360.0-Pitch_F)*TWO_PI/360.0)* cos((Roll_F-180.0)*TWO_PI/360.0) - ax_F * sin((360.0-Pitch_F)*TWO_PI/360.0) + ay_F * sin((Roll_F-180.0)*TWO_PI/360.0); 
          base_az_g    = az_F * cos((Pitch_F)*TWO_PI/360.0)* cos((Roll_F)*TWO_PI/360.0) - ax_F * sin((Pitch_F)*TWO_PI/360.0) + ay_F * sin((Roll_F)*TWO_PI/360.0); 
          //Serial.printf("setup base_az_g = %f, ax_F = %f, ay_F = %f, az_F = %f, Pitch_F = %f, Roll_F = %f, Yaw_F = %f\n", base_az_g, ax_F, ay_F, az_F, Pitch_F, Roll_F, Yaw_F);          
          //Serial.printf("base_az_g = %f\n", base_az_g);
        }

        //Serial.printf(" Yaw = %f\n", Yaw_F);     

//        TL   = command_p+8;        
//        TH   = command_p+9;           
//        T    = (uint16_t)(*TH<<8)|(uint16_t)*TL;        
//        T_F  = T/100.0f;   
        //Serial.printf(" T = %f\n", T_F);     
                            
        break;     

      case 0x5554:     
        //磁场(x 轴)Hx=(( HxH<<8)| HxL)
        //磁场(y 轴)Hy=(( HyH <<8)| HyL)
        //磁场(z 轴)Hz=(( HzH<<8)| HzL)
        HxL   = command_p+2;        
        HxH   = command_p+3;           
        Hx    = (uint16_t)(*HxH<<8)|(uint16_t)*HxL;        
        Hx_F  = (Hx/32768.0f)*180.0f;  
        //Serial.printf(" HxL = %d\n", *HxL);  
        //Serial.printf(" HxH = %d\n", *HxH);       
        //Serial.printf(" Hx = %d\n", Hx);           
        //Serial.printf(" Hx = %f\n", Hx_F);    
        
        HyL   = command_p+4;        
        HyH   = command_p+5;           
        Hy    = (uint16_t)(*HyH<<8)|(uint16_t)*HyL;        
        Hy_F  = (Hy/32768.0f)*180.0f;  
        //Serial.printf(" Hy = %f\n", Hy_F);  
        
        HzL   = command_p+6;        
        HzH   = command_p+7;           
        Hz    = (uint16_t)(*HzH<<8)|(uint16_t)*HzL;        
        Hz_F  = (Hz/32768.0f)*180.0f;   
        //Serial.printf(" Hz = %f\n", Hz_F);     

//        TL   = command_p+8;        
//        TH   = command_p+9;           
//        T    = (uint16_t)(*TH<<8)|(uint16_t)*TL;        
//        T_F  = T/100.0f;   
//        Serial.printf(" T = %f\n", T_F);      
        break;    

      case 0x5556:      

        Height = ((uint32_t)(*(command_p+6)) + (uint32_t)(*(command_p+7)<<8) + (uint32_t)(*(command_p+8)<<16) + (uint32_t)(*(command_p+9)<<24))/10;  //cm
        Height = Height *z_ratio; // adjust ratio
        //Serial.printf("H0 = %x, H1 = %x,H2 = %x,H3 = %x, Height = %d \n", *(command_p+6), *(command_p+7), *(command_p+8), *(command_p+9), Height);
        if (before_loop == 1)
        {
          base_height   = Height;
          base_height_F = (double)base_height;
          //Serial.printf("base_height = %d\n", base_height);
        } 
        //Serial.printf("0x5556====== millis = %d\n",   millis() ); //around 160ms for a loop     
        break;   
       
    }
    serial2_left_bytes  -= COMMAND_SEGMENT_LENGTH;  
    command_p           += COMMAND_SEGMENT_LENGTH;
    new_JY901S_packet = 1;
    
  }
  //Serial.printf("millis = %d\n",   millis() ); //around 160ms for a loop        
  //Serial.printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");      
}
 
init.cpp
////
#include <Arduino.h>
#include "init.h"

// UART1: balance_platform
// UART2: JY901S

uint8_t UART1_received[DATA_SIZE + 1];
uint8_t UART2_received[DATA_SIZE + 1];

// balance_platform command
// 绝对时间指的是以第一条运动数据指令开始计算的时间值,单位是毫秒。L 表示四字节长度的整数。
// 电机的绝对位置,每个轴的位置数据都是 4 字节长度的,高位在前的,有符号整数。0xff ff ff ff 表示-1 位

uint8_t UART1_TX_COMMAND_1[] = { 0x55, 0xAA, 0x00, 0x00, 0x14, 0x01 , 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,   // 16 per line
                                 0x00, 0x00, 0x03, 0x20, 0x00, 0x02, 0xE3, 0x6B, 0x00, 0x02, 0xE3, 0x6B, 0x00, 0x02, 0xE3, 0x6B,
                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                               };

// up 100mm
uint8_t cmd_t0_CH9121_Up100mm[] = {0x55, 0xAA, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xFF, 0xFF,
                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1F, 0x40, //8000
                                   0x00, 0x01, 0xE5, 0xFC, 0x00, 0x01, 0xE5, 0xFC,  0x00, 0x01,
                                   0xE5, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                                  };    // 38 bytes

uint8_t cmd_t0_CH9121_Up130mm[] = {0x55, 0xAA, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xFF, 0xFF,
                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1F, 0x40, //8000
                                   0x00, 0x02, 0x41, 0x21, 0x00, 0x02, 0x41, 0x21,  0x00, 0x02,
                                   0x41, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                                  };    // 38 bytes

uint8_t cmd_t0_CH9121_Up170mm[] = {0x55, 0xAA, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xFF, 0xFF,
                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1F, 0x40, //8000
                                   0x00, 0x02, 0xBF, 0x6A, 0x00, 0x02, 0xBF, 0x6A,  0x00, 0x02,
                                   0xBF, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                                  };    // 38 bytes

// up 200mm
uint8_t cmd_t0_CH9121_Up200mm[] = {0x55, 0xAA, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xFF, 0xFF,
                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1F, 0x40, //8000
                                   0x00, 0x03, 0xD0, 0xA4, 0x00, 0x03, 0xD0, 0xA4,  0x00, 0x03,
                                   0xD0, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                                  };    // 38 bytes

// original
// uint8_t cmd_t0_CH9121_Original[] = {0x55, 0xAA, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xFF, 0xFF,
//                            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x13, 0x88, //5000
//                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};    // 38 bytes
uint8_t cmd_t0_CH9121_Original[] = {0x55, 0xAA, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xFF, 0xFF,
                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1F, 0x40, //8000
                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
                                   };    // 38 bytes


// JY901S command

// save config: { 0xFF, 0xAA, 0x00, SAVE, 0x00 };
/*
  0:保持当前配置
  1:恢复默认(出厂)配置并保存
*/
uint8_t UART2_UNLOCK_COMMAND_69[] = { 0xFF, 0xAA, 0x69, 0x88, 0xB5};
uint8_t UART2_SAVE_COMMAND_00[] = { 0xFF, 0xAA, 0x00, 0x00, 0x00};

// set report contain: { 0xFF, 0xAA, 0x02, RSWL, RSWH };
// RSWL
// 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50
// RSWH
// X, X, X, X, X, 0x5A, 0x59, 0x58

// 0x57 经纬度包         8
// 0x56 气压&高度包      4
// 0x55 端口状态         2
// 0x54 磁场信息包       1
// 0x53 角度信息包       8
// 0x52 角速度信息包     4
// 0x51 加速度信息包     2
// 0x50 时间信息包       1

// 0x5A 卫星定位精度     4
// 0x59 四元素输出包     2
// 0x58 地速数据包       1


uint8_t UART2_return_data_COMMAND_02[] = { 0xFF, 0xAA, 0x02, 0x4A, 0x00};

//
// set report rate: { 0xFF, 0xAA, 0x03, RATE, 0x00 };
/*
    RATE:回传速率
    0x00:0.1Hz  // no such
    0x01:0.2Hz
    0x02:0.5Hz
    0x03:1Hz
    0x04:2Hz
    0x05:5Hz
    0x06:10Hz(默认)  // fit 9600
    0x07:20Hz
    0x08:50Hz
    0x09:100Hz        // fit 115200
    0x0a:无(保留)
    0x0b:200Hz
    0x0c:单次输出
*/

/*
  RATE:return rate
  0x01:0.1Hz
  0x02:0.5Hz
  0x03:1Hz
  0x04:2Hz
  0x05:5Hz
  0x06:10Hz(default)
  0x07:20Hz
  0x08:50Hz  // don't over this rate, CPU can't afford to more than 50Hz/20ms
  0x09:100Hz  <---
  0x0a:125Hz
  0x0b:200Hz
  0x0c:Single
  0x0d: Not output
*/

uint8_t UART2_REPORT_RATE_COMMAND_03[] = { 0xFF, 0xAA, 0x03, 0x07, 0x00};
// rate 00 is not work

/**********************************
  set baudrate: {0xFF, 0xAA, 0x04, BAUD, 0x0}
  BAUD:波特率设置
  0x00:2400
  0x01:4800
  0x02:9600(默认)
  0x03:19200
  0x04:38400
  0x05:57600
  0x06:115200
  0x07:230400  <<----------------------
  0x08:460800
  0x09:921600
************************************/
uint8_t UART2_REPORT_BAUD_RATE_COMMAND_04[] = { 0xFF, 0xAA, 0x04, 0x07, 0x00};

//Serial使用GPIO1->TX0,GPIO3->RX0,通常用於USB通訊和寫程式debug使用,預設系統使用
//Serial1使用GPIO10->TX1,GPIO9->RX1,通常用於SPI flash上,預設系統未使用
//Serial2使用GPIO17->TX2,GPIO16->RX2,通常用於自行使用,大部分的人都會使用這個,預設系統未使用

void init_serial(void) {
  // UART0 will be used to log information into Serial Monitor
  Serial.begin(115200);
  //Serial.onReceive(onReceiveUart0_from_console, true);  // sets a RX callback function for Serial 1

  // Serial1 for platform
  Serial1.begin(BAUD1, SERIAL_8N1, RX1PIN, TX1PIN);  // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3
  Serial1.setRxTimeout(RXTIMEOUT);
  Serial1.setRxFIFOFull(FIFIFULL);
  //Serial1.onReceive(onReceiveUart1_from_balance_platform, true);  // sets a RX callback function for Serial 1

  // Serial2 for JY901S
  Serial2.begin(230400, SERIAL_8N1, RX2PIN, TX2PIN);  // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3
  //Serial2.begin(9600, SERIAL_8N1, RX2PIN, TX2PIN);  // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3
  Serial2.setRxTimeout(RXTIMEOUT);
  Serial2.setRxFIFOFull(FIFIFULL);
  Serial2.onReceive(onReceiveUart2_from_JY901S, true);  // sets a RX callback function for Serial 1
  Serial.printf("init_serial done\n");
}

void init_platform(void) {

  int bytesSent;

  bytesSent = Serial1.write(cmd_t0_CH9121_Up100mm, sizeof(cmd_t0_CH9121_Up100mm));
  //Serial.printf("1. bytesSent length = %d\n", bytesSent);
  //cmd_t0_CH9121_Original
  delay(5000);

  //bytesSent = Serial1.write(cmd_t0_CH9121_Original, sizeof(cmd_t0_CH9121_Original));
  //Serial.printf("2. bytesSent length = %d\n", bytesSent);

}

void init_JY901S(void) {
  // set report rate
  // 0xFF 0xAA 0x03 RATE 0x00


  int bytesSent;

  //bytesSent = Serial2.write(UART2_UNLOCK_COMMAND_69, sizeof(UART2_UNLOCK_COMMAND_69)); //JY901s use this command, JY61P not use this
  //Serial.printf("bytesSent length of UART2_UNLOCK_COMMAND_69 = %x\n", 0x6988B5);
  delay(1);
  bytesSent = Serial2.write(UART2_return_data_COMMAND_02, sizeof(UART2_return_data_COMMAND_02));
  //Serial.printf("bytesSent length of UART2_return_data_COMMAND_02 = %x\n", UART2_return_data_COMMAND_02[3]);
  delay(1);
  bytesSent = Serial2.write(UART2_REPORT_RATE_COMMAND_03, sizeof(UART2_REPORT_RATE_COMMAND_03));
  //Serial.printf("bytesSent length of UART2_REPORT_RATE_COMMAND_03 = %x\n", UART2_REPORT_RATE_COMMAND_03[3]);
  delay(1);

  // must change init_serial()/Serial2.begin(BAUD2==>115200, after "reboot"
  bytesSent = Serial2.write(UART2_REPORT_BAUD_RATE_COMMAND_04, sizeof(UART2_REPORT_BAUD_RATE_COMMAND_04));
  //Serial.printf("bytesSent length of UART2_REPORT_BAUD_RATE_COMMAND_04 = %x\n", UART2_REPORT_BAUD_RATE_COMMAND_04[3]);
  delay(1);
  bytesSent = Serial2.write(UART2_SAVE_COMMAND_00, sizeof(UART2_SAVE_COMMAND_00));
  //Serial.printf("bytesSent length of UART2_SAVE_COMMAND_00 = %d\n", UART2_SAVE_COMMAND_00[3]);
}

init.h
#include <Commander.h>
#include "WiFi.h"
//#include <WebServer.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
#include <HTTPClient.h>
#include "time.h"
#include <ESPmDNS.h>

// Serial
#define TX0PIN       1       // used by USB/UART/Serial
#define RX0PIN       3       // used by USB/UART/Serial
#define BAUD0        115200     // Any baudrate from 300 to 115200

//Serial1            // connect to ethernet module
#define TX1PIN       10      // used by USB/UART/Serial1
#define RX1PIN       9       // used by USB/UART/Serial1
#define BAUD1        115200//38400 //57600 //115200     // Any baudrate from 300~921600bps

//Serial2            // connect to JY901s
#define TX2PIN       17       // used by USB/UART/Serial2
#define RX2PIN       16       // used by USB/UART/Serial2
#define BAUD2        115200   // Any baudrate from 300 to 115200

#define RXTIMEOUT    50  //minisecond 
#define FIFIFULL     32  // byte
#define DATA_SIZE    500
#define COMMAND_SEGMENT_LENGTH   11

#define FOLLOWING_MODE     1
#define COMPENSATION_MODE -1

#define MAX_LENGTH 200

#define EEPROM_SIZE 128

struct MyStructure {  
  uint16_t omission;
  int8_t   reaction_mode;
  double   rotation_quota;  
  uint8_t  show_angle;
  uint8_t  show_height;
  uint8_t  show_length;
  int16_t step;
  double   toward_step;  
  uint8_t  transmission_adjust;
  double   z_quota;  
  uint16_t z_ratio;    
  int16_t  degree_quota;  
};

void init_serial(void);
void normalize_angle(void);
void onReceiveUart0_from_console(void);
void onReceiveUart1_from_balance_platform(void);
void onReceiveUart2_from_JY901S(void);
void init_JY901S(void);
void init_platform(void);
void initialiseCommander(void);
void init_WiFi(void);
void init_WebServer(void);
//void WebServer( void * pvParam );
//void task_platform(void * pvParam );

bool degree_quota_IntHandler(Commander &Cmdr);
bool getFloatHandler(Commander &Cmdr);
bool omission_IntHandler(Commander &Cmdr);
bool reaction_StringsHandler(Commander &Cmdr);
bool reset_default_parameter_structHandler(Commander &Cmdr);
bool rotation_quota_FloatHandler(Commander &Cmdr);
bool save_parameter_structHandler(Commander &Cmdr);
bool show_angle_IntHandler(Commander &Cmdr);
bool show_height_IntHandler(Commander &Cmdr);
bool show_length_IntHandler(Commander &Cmdr);
bool show_parameter_structHandler(Commander &Cmdr);
bool step_IntHandler(Commander &Cmdr);
bool transmission_adjust_IntHandler(Commander &Cmdr);
bool toward_step_FloatHandler(Commander &Cmdr);
bool z_quota_FloatHandler(Commander &Cmdr);
bool z_ratio_IntHandler(Commander &Cmdr);
bool helloHandler(Commander &Cmdr);
bool hiddenHandler(Commander &Cmdr);
bool setFloatHandler(Commander &Cmdr);
bool setFloatsHandler(Commander &Cmdr);
bool setIntHandler(Commander &Cmdr);
bool setIntsHandler(Commander &Cmdr);
bool setStringsHandler(Commander &Cmdr);

void set_degree_quota(void);
bool reset_default_parameter(void);
bool save_parameter(void);
//extern AsyncWebServer server(80);

extern MyStructure reserved_data;

extern uint16_t omission;
extern int8_t   reaction_mode;
extern double   rotation_quota;
extern uint8_t  show_angle;
extern uint8_t  show_height;
extern uint8_t  show_length;
extern int16_t  step;
extern double   toward_step;  
extern uint8_t  transmission_adjust;
extern double   z_quota;
extern uint16_t z_ratio;  
extern int16_t  degree_quota;
extern Commander cmd;
extern uint8_t new_JY901S_packet;
extern uint8_t UART0_received[DATA_SIZE + 1];
extern uint8_t UART1_received[DATA_SIZE + 1];
extern uint8_t UART2_received[DATA_SIZE + 1];

extern uint8_t cmd_t0_CH9121_REACTION[];

extern uint8_t cmd_t0_CH9121_Up100mm[];
extern uint8_t cmd_t0_CH9121_Up130mm[];
extern uint8_t cmd_t0_CH9121_Up170mm[];
extern uint8_t cmd_t0_CH9121_Up200mm[];
extern uint8_t cmd_t0_CH9121_Original[];

extern uint8_t serial0_received_bytes; 
extern uint8_t serial1_received_bytes; 
extern uint8_t serial2_received_bytes;


// read current as base number
extern double base_Roll_F;    
extern double base_Pitch_F; 
extern double base_Yaw_F;  

extern int32_t  Height; 
extern int32_t  base_height;
extern double   base_height_F; 
extern double   toward_step;
extern uint8_t  before_loop;
extern uint8_t *TH, *TL;
extern uint16_t T;
extern double   T_F;

// 0x5551  variables
extern double base_az_g;

extern uint8_t *axH, *axL;
extern uint16_t ax;
extern int16_t *ax_p;
extern double   ax_F;

extern uint8_t *ayH, *ayL;
extern uint16_t ay;
extern int16_t *ay_p;
extern double   ay_F;

extern   uint8_t *azH, *azL;
extern   uint16_t az;
extern   int16_t *az_p;
extern   double   az_F;
  
// 0x5552  variables

extern   uint8_t *wxH, *wxL;
extern   uint16_t wx;
extern   double wx_F;

extern   uint8_t *wyH, *wyL;
extern   uint16_t wy;
extern  double    wy_F;

extern  uint8_t *wzH, *wzL;
extern  uint16_t wz;
extern  double   wz_F;

// 0x5553  variables
extern  uint8_t *RollH, *RollL;
extern  uint16_t Roll;
extern  double   Roll_F;
extern volatile int16_t  Roll_INT;  

extern  uint8_t *PitchH, *PitchL;
extern  uint16_t Pitch;
extern  double   Pitch_F;
extern volatile int16_t  Pitch_INT;  

extern  uint8_t *YawH, *YawL;
extern  uint16_t Yaw;
extern  double   Yaw_F;

// 0x5554  variables
extern  uint8_t *HxH, *HxL;
extern  uint16_t Hx;
extern  double   Hx_F;

extern  uint8_t *HyH, *HyL;
extern  uint16_t Hy;
extern  double   Hy_F;

extern  uint8_t *HzH, *HzL;
extern  uint16_t Hz;
extern  double   Hz_F;

masterCommander.cpp






this is my first time try using forum to help me to solve problem. if there any action not following the rule of forum, please let me know. The code is large that my browser told me memory is not enough, I didn't upload all my code. If there no sufficient code to realize the issue, I will upload rest code later.

Since you have no clue where it is failing, step one would be to put print statements at every few "steps" of the code, to see how far it is getting before crashing. Follow each print statement with Serial.flush() to make sure the message gets out BEFORE proceeding to the next step. The LAST message printed will tell you the last step that succeeded, and the problem will be between that print statement and the next one. Add/remove print statements to narrow the range of the search as needed.

Thanks! I think I've found the reason. When a crash occurs, error messages are of the following types:

  1. Assertion failed: tcp_sent /IDF/components/lwip/lwip/src/core/tcp.c:2050 (the socket status transmitting the callback is invalid)
  2. Assertion failed: block_locate_free tlsf.c:566 (block_size(block) >= size)
  3. Assertion failed: multi_heap_free multi_heap_poisoning.c:276 (head != NULL)
  4. Watchdog failure

I found that when the crash occurred, the ping response time became very large, even reaching 900ms. So I tried closing the connection to the local WiFi network(path: client browser --- office AP --- ESP32) and just letting the client browser web server connect directly(path: client browser --- ESP32) to the ESP32. The ping response time reduce to under 100ms. Then I don't see the crash happening again. I think the root cause is the response time to large,

While waiting for the ping response, call delay() or yield(), to keep the watchdog from firing. Also, provide a timeout in case the response NEVER comes. NEVER create a wait loop that does not contain some kind of escape if whatever it's waiting for never happens.

(anecdotally) I have had similar problems with a webserver on an ESP8266 and switching to LittleFS has been the solution.