Arduino Mega 2560 - 成功执行多次后在 while 循环中停止代码执行

Posted

技术标签:

【中文标题】Arduino Mega 2560 - 成功执行多次后在 while 循环中停止代码执行【英文标题】:Arduino Mega 2560 - stops code execution in while loop after successfully executing several times 【发布时间】:2022-01-16 14:28:02 【问题描述】:

我目前正在使用 arduino Mega 2560、duinotech 3 向磁力计(5883L 仿制)和带有板载 ariel 的 duinotech gps 接收器完成一个自动 gps 漫游者项目。所有组件在 arduino 上运行良好,并且在主循环中执行没有问题。

...
void loop()

  bluetooth();
  delay(10); // Run the Bluetooth procedure to see if there is any data being sent via BT                                                    
  getGPS();  
  delay(10); // Update the GPS location
  getCompass();
  // Serial.println(compass_heading);
  delay(10);
  // Update the Compass Heading

...

但是,一旦我设置了一些航点并启用了自动驾驶功能,程序就会执行 4 次循环然后失败。

有问题的函数

...
void goWaypoint()
   
    Serial.println(F("Go to Waypoint"));
    ac=ac-1;

    while (true)  
                                                                    // Start of Go_Home procedure 
        // bluetooth();                                                     // Run the Bluetooth procedure to see if there is any data being sent via BT
        // if (blueToothVal == 4)
        //   
        //   Serial.println("Bluetooth Break");
        //   break;
        //                                      // If a 'Stop' Bluetooth command is received then break from the Loop
        if (ac==-1)
            break;
        
        Serial.println(F("Checking Compass"));
        getCompass();  
        delay(80);// Update Compass heading  
        Serial.println(F("Checking GPS"));                                        
        getGPS(); 
        delay(20);
        // Tiny GPS function that retrieves GPS data - update GPS location// delay time changed from 100 to 10
  
        if (millis() > 5000 && gps.charsProcessed() < 10) 
                       // If no Data from GPS within 5 seconds then send error
            Serial.println(F("No GPS data: check wiring"));     
        
        Serial.println(F("Calculating"));
        Distance_To_Home = TinyGPSPlus::distanceBetween(gps.location.lat(),gps.location .lng(),Home_LATarray[ac], Home_LONarray[ac]);  //Query Tiny GPS for Distance to Destination
        GPS_Course = TinyGPSPlus::courseTo(gps.location.lat(),gps.location.lng(),Home_LATarray[ac],Home_LONarray[ac]);                               //Query Tiny GPS for Course to Destination   
        Serial.println(F("The Distance to waypoint: "));
        Serial.println(Distance_To_Home);
        Serial.println(F("The GPS Course Needed: "));
        Serial.println(GPS_Course);
    
        if (Distance_To_Home <= 1.5)                                   // If the Vehicle has reached it's Destination, then Stop
        
            StopCar();                                               // Stop the robot after each waypoint is reached
            Serial.println(F("You have arrived!"));                    // Print to Bluetooth device - "You have arrived"          
            ac--;                                                    // increment counter for next waypoint
            if (ac==-1) 
                break;
                                                               // Break from Go_Home procedure and send control back to the Void Loop                                                                  // go to next waypoin      
           
        else if ( abs(GPS_Course - compass_heading) <= 30)                  // If GPS Course and the Compass Heading are within x degrees of each other then go Forward                                                                                                                                    
                                                                  // otherwise find the shortest turn radius and turn left or right
           Forward();                                               // Go Forward
        
        else 
                                                               
            int x = (GPS_Course - 360);                           // x = the GPS desired heading - 360
            int y = (compass_heading - (x));                      // y = the Compass heading - x
            int z = (y - 360);                                    // z = y - 360
            
            if ((z <= 180) && (z >= 0))                           // if z is less than 180 and not a negative value then turn left otherwise turn right
             
                 Serial.println(F("Turning Left:"));
                 SlowLeftTurn();
            
            else 
             
                Serial.println(F("Turning Right"));
                SlowRightTurn(); 
                           
         
                                                                  // End of While Loop 
                                                                // End of Go_Home procedure
...

最后是连接到仪器的两个函数

void getGPS()                                                 // Get Latest GPS coordinates

    while (Serial2.available() > 0)
    gps.encode(Serial2.read());
    delay(60);
 

void getCompass()                                               // get latest compass value
  

    Vector norm = compass.readNormalize();

    float declinationAngle = (21.5 + (26.0 / 60.0)) / (180 / M_PI);

    // Calculate heading
    float heading = atan2(norm.YAxis, norm.XAxis);
    heading += declinationAngle;
    // heading = heading-0.4;
 
    if(heading < 0)
        heading += 2 * M_PI;      
    compass_heading = (int)(heading * 180/M_PI);  
    delay(100);                 // assign compass calculation to variable (compass_heading) and convert to integer to remove decimal places                                                              


上面提到的代码开始运行然后失败,只是在第四次通过 getCompass() 调用之后(大部分延迟和输出是在我的调试尝试中添加的)。我怀疑可能是内存泄漏????任何建议/帮助将不胜感激。

冻结的图片 code halted

编辑:在 getCompass() 中添加了更多打印 ...

void getCompass()                                               // get latest compass value
  
    Serial.println(F("In getCompass"));
    Vector norm = compass.readNormalize();

    float declinationAngle = 0.418;

    // Calculate heading
    Serial.println(F("Before Atan"));
    float heading = atan2(norm.YAxis, norm.XAxis);
    heading += declinationAngle;
    // heading = heading-0.4;
    Serial.println(F("Positive Balance"));
    if(heading < 0)
        heading += 2 * M_PI;  
    Serial.println(F("Radians to degrees"));    
    compass_heading = (int)(heading * 180/M_PI);  
    delay(100);                 // assign compass calculation to variable (compass_heading) and convert to integer to remove decimal places                                                              
    Serial.println(F("Get Compass Finished"));

... 结果是调用在“In compass”打印后冻结,因此问题可能是 compass.normalise 函数。

我是 arduino 和低级编码的初学者,所以不确定现在如何进行,为什么在主循环中调用时它可以正常工作,但在这个 while 循环中占用代码?

更新的执行屏幕 Error Screen

我正在使用的指南针库https://github.com/jarzebski/Arduino-HMC5883L

编辑 2:在 getCompass() 中进一步弄乱我设法通过注释使代码正常工作。

float declinationAngle = 0.418;
heading += declinationAngle;

我现在完全迷失了,为什么这会导致代码冻结,以及在不使用浮点数的情况下消除偏角以计算方向的最佳方法是什么。

编辑 3:添加以包括指南针设置。

void setup() 
  
  
  Serial.begin(115200);                                            // Serial 0 is for communication with the computer and magnometer.
  Serial.println("In Setup");
  // Serial1.begin(11520);                                             // Serial 1 is for Bluetooth communication - DO NOT MODIFY - JY-MCU HC-010 v1.40
  Serial2.begin(9600);                                             // Serial 2 is for GPS communication at 9600 baud - DO NOT MODIFY - Ublox Neo 6m  
  // Motors
  pinMode(leftMotor, OUTPUT);
  pinMode(rightMotor, OUTPUT);
  // bluetooth buffer
  indx = 0;
  // Compass
  Serial.println("Compass setup");
  while (!compass.begin()) 
                         
    Wire.begin();                             // Join I2C bus used for the HMC5883L compass
    Serial.println("Bus OK");
    compass.begin();                                                 // initialize the compass (HMC5883L)
    Serial.println("Compass Object Created");
    compass.setRange(HMC5883L_RANGE_1_3GA);                          // Set measurement range  
    compass.setMeasurementMode(HMC5883L_CONTINOUS);                  // Set measurement mode  
    compass.setDataRate(HMC5883L_DATARATE_15HZ);                     // Set data rate  
    compass.setSamples(HMC5883L_SAMPLES_8);                          // Set number of samp5les averaged  
    compass.setOffset(65,-290);                                          // Set calibration offset
    Serial.println("Calibrated Compass");
  
  Serial.println("Setup Complete");
  Startup();                                                       // Run the Startup procedure on power-up one time

startup() 函数作为设置的一部分:

void Startup()

      
     for (int i=5; i >= 1; i--)                       // Count down for X seconds
               
        Serial.print("Pause for Startup... "); 
        Serial.print(i);
        delay(1000);                                   // Delay for X seconds
          
  Serial.println("Searching for Satellites ");     
  while (Number_of_SATS < 4)                         // Wait until x number of satellites are acquired before starting main loop
                
    Serial.println("Small delay for home co-ordinates to be recieved");
    delay(10);                    
    getGPS();                                         // Update gps data
    Serial.print("Number of Sats: ");
    Serial.println(int(gps.satellites.value()));
    Number_of_SATS = (int)(gps.satellites.value());   // Query Tiny GPS for the number of Satellites Acquired       
    bluetooth();                                      // Check to see if there are any bluetooth commands being received  
    Serial.println("Looping for SATS"); 
                                          // set intial waypoint to current location
  wpCount = 0;                                        // zero waypoint counter
  ac = 0;                                             // zero array counter 
  Serial.print(Number_of_SATS);
  Serial.print(" Satellites Acquired");
  Serial.println(" Start-up Complete");   
 

【问题讨论】:

getCompass() 中,您调用readNormalize()atan2(),这两个可能的罪魁祸首。您是否添加了更多打印以查看执行停止的位置? 完成。最后更新了原始问题中的编辑。似乎是 readNormalize() 你有什么建议为什么会导致这种情况以及解决它的最佳方法? 在原始问题中添加了进一步的发现 您正在使用的 readNormalize() 函数调用 readRegister16() 通过 i2c 读取几个 HMC5883L 寄存器。库函数readRegister16() 会阻塞等待 i2c 回复:while(!Wire.available()) ; 因此,如果磁力计没有回复,您将永远被卡住。您的设置是否有足够的功率?电动移动装置的电流消耗会非常不均匀,因此电流峰值可能与电压下降(可能是电池电量不足)同时出现。所有的线都连接牢固了吗? 电源很稳定,但是接线是……有点狡猾,主要是因为我在这个项目上学习焊接。然而,这些线路通过万用表的连接测试。在昨天进一步弄乱它时,我发现可以通过取出 getCompass() 函数中的浮点减法并将其作为常量浮点数与其余的变量减法来消除冻结。但是,我不知道为什么或如何消除冻结。 【参考方案1】:

所以我设法通过从 getCompass() 函数中取出 float 声明并将其声明为全局 const float 来解决问题。为什么这会导致错误以及为什么在作为 goWaypoint() 函数的一部分运行时会发生错误我不知道,所以如果有人知道原因,请随时添加到这个问题中。同时,我将把这个答案留在这里,以防其他用户遇到类似问题。

更新:这在 24 小时内仍然没有解决,无人机的代码没有任何变化,回到了代码在 getCompass() 函数中被占用的相同情况,唯一的区别是现在它正在占用矢量范数 = compass.normalize() 线。我尝试将函数中的所有变量设置为全局变量而不是局部变量,但这没有任何效果。我开始怀疑这是否可能是主板的硬件问题。

【讨论】:

看看here 测量空闲 RAM 的方法,因为您怀疑 堆栈溢出。您发布的代码不完整,所以我可以'不知道有多少 RAM 用于其他事情 谢谢,该链接最有帮助。完整的程序在上传时占用 6% 的程序内存空间,16% 的动态内存和变量。将局部变量移到全局变量已经解决了这个问题,因为我现在有时间运行一些冗长的测试,所以我猜测在本地声明它时肯定会发生一些内存分配恶作剧。 对我来说这听起来像是堆栈损坏,而不是内存泄漏。您如何声明 Vector 数据类型和定义+初始化的指南针?你的setup() 里有什么? 在主帖中进行了一些编辑以显示包含指南针初始化的设置。该向量来自我使用的指南针库github.com/jarzebski/Arduino-HMC5883L,我相信它又使用了来自 hmc588L 库的它。它很有可能不是内存泄漏,这更像是我在黑暗中未受过教育的刺伤。 今天对车辆的测试遇到了失败,请参阅上面的编辑。

以上是关于Arduino Mega 2560 - 成功执行多次后在 while 循环中停止代码执行的主要内容,如果未能解决你的问题,请参考以下文章

arduino mega2560是多少位的单片机

(Arduino Mega2560)键盘密码检查

Arduino MEGA 2560找不到驱动怎么办

arduino UNO r3和arduino mega2560 用esp8266 01的WiFi模块可以接入百度天工物联网平台吗?

Python 没有接收到来自 Arduino Mega 2560 的第一行串行数据,而是接收到所有后续数据,为啥会发生这种情况?

win7下Arduino Mega 2560驱动安装失败解决办法