在ESP32的 C++中损坏对象变量

编程语言 2026-07-11

我正在为ESP32创建一个项目。对ESP和 C++编程还算是新手。我在VSCode里使用PlatformIO。

它是一台会在周围巡游的机器人。它装有超声波传感器,用来探测障碍物。 传感器。 我把每个传感器的引脚信息存放在ProximitySensor类型的对象里。

运行时,存储的引脚值会改变,似乎变成了任意的数值。

下面是表示这些传感器的类:

class ProximitySensor : public potbot::Sensor
{
private:
    const int pin_trig;
    const int pin_echo;
    const int16_t orientation; // degrees relative to middle axis (front = 0°)

public:
    ProximitySensor(const int pin_trig, const int pin_echo, const int16_t orientation);
    void setup() override;
    float read() override;
    int16_t getOrientation(){return orientation;}
};

以及相应的实现:

ProximitySensor::ProximitySensor(const int pin_trig, const int pin_echo, const int16_t orientation) : Sensor("Proximity Sensor"), pin_trig(pin_trig), pin_echo(pin_echo), orientation(orientation) {
    //setup();

}

void ProximitySensor::setup(){
    Serial.println("Proximity sensor initialized with trig pin " + String(pin_trig) + " and echo pin " + String(pin_echo) + " at orientation " + String(orientation));
    pinMode(pin_trig, OUTPUT);
    pinMode(pin_echo, INPUT);
}

float ProximitySensor::read(){
    delay(10);
    Serial.println("reading prox sensors pins at: " + String(orientation));
    Serial.print("pin_trig = "+ String(pin_trig) + " pin_echo = " + String(pin_echo));
    Serial.println();
    digitalWrite(pin_trig, LOW);
    delayMicroseconds(2);
    digitalWrite(pin_trig, HIGH);
    delayMicroseconds(10);
    digitalWrite(pin_trig, LOW);

    unsigned long duration = pulseIn(pin_echo, HIGH);

    long dist = duration * SOUND_SPEED / 2;
    return dist;
}

在主文件中,我按如下方式创建了它的五个对象:

ProximitySensor *prox_sensors[5] = {new ProximitySensor(23, 36, 0),
                                    new ProximitySensor(22, 39, -25),
                                    new ProximitySensor(19, 35, 25),
                                    new ProximitySensor(18, 32, -120),
                                    new ProximitySensor(21, 34, 120)};

并在main的 setup() 函数中调用它们的setup()。

接着我会定期读取它们。问题就出现在这里,显示出任意的数值。

这是串口监视器日志中的一个示例:

reading prox sensor at: 0 degrees
pin_trig = 23, pin_echo = 36
reading prox sensor at: 20924 degrees
pin_trig = -1413869004, pin_echo = 20
E (12594) gpio: gpio_set_level(227): GPIO output gpio_num error
E (12596) gpio: gpio_set_level(227): GPIO output gpio_num error
E (12601) gpio: gpio_set_level(227): GPIO output gpio_num error
reading prox sensor at: 22136 degrees
pin_trig = 39, pin_echo = 1027538919
E (13617) gpio: gpio_set_level(227): GPIO output gpio_num error
E (13618) gpio: gpio_set_level(227): GPIO output gpio_num error
E (13624) gpio: gpio_set_level(227): GPIO output gpio_num error
reading prox sensor at: 20896 degrees
pin_trig = 20, pin_echo = 1061179836
reading prox sensor at: 32 degrees
pin_trig = -949616615, pin_echo = -1163045256

还需要注意的是,每次读取时,值都是不同的。

我已经检查过的事项:

  • 可用内存:使用 ESP.getFreeHeap()ESP.getMaxAllocHeap() 时,总内存超过200KB,最大的区块约110KB。
  • 越界写入数组:修正了一个潜在的情况,但数据损坏仍然存在。

提前致谢,欢迎任何建议。

编辑(可复现的示例):

main.cpp:

#ifndef POTBOT_INO
#define POTBOT_INO

#include <Arduino.h>
#include "Globals.h"
#include "sensors/impl/ProximitySensor.h"
#include "navigation/NavigationManager.h"

void setupProxSensors();
void updateObstacles();

ProximitySensor *prox_sensors[5] = {new ProximitySensor(23, 36, 0),
                                    new ProximitySensor(22, 39, -25),
                                    new ProximitySensor(19, 35, 25),
                                    new ProximitySensor(18, 32, -120),
                                    new ProximitySensor(21, 34, 120)};

ulong tick = 0;
long lastObstacleUpdate = 0;

NavigationManager driveManager(prox_sensors[0]);

void setup()
{
  Serial.begin(115200);
  delay(500);
  setupProxSensors();
}

void loop()
{
  tick++;
  updateObstacles();
  delay(10); 
  if(tick % 100 == 0){
    Serial.println(".....................");
    Serial.print("free heap: ");
    Serial.println(ESP.getFreeHeap());
    Serial.print("biggest free chunk: ");
    Serial.println(ESP.getMaxAllocHeap());
  }
}

void updateObstacles()
{
  if (millis() - lastObstacleUpdate > 5000)
  {
    driveManager.updateMapFromSensors(false);
    lastObstacleUpdate = millis();
  }
}

void setupProxSensors()
{
  for (uint8_t i = 0; i < PROX_SENSOR_COUNT; i++)
  {
    ProximitySensor *sensor = prox_sensors[i];
    sensor->setup();
  }
}
#endif

NavigationManager.h:

#ifndef DRIVERMANAGER_H
#define DRIVERMANAGER_H

#define OBS_GRID_SIZE 50
#define OBS_CELL_SIZE 20

#include <cstdint>
#include "../sensors/impl/ProximitySensor.h"
#include "Globals.h"

class NavigationManager
{
private:
    uint8_t obstacleGrid[OBS_GRID_SIZE][OBS_GRID_SIZE];
    int x, y;
    float heading;
    ProximitySensor *proxSensors;

public:
    NavigationManager(ProximitySensor *prxSns) : x(0), y(0), heading(0), proxSensors(prxSns) {}
    void updateMapFromSensors(bool isExploring_p)
    {
        for (int i = 0; i < PROX_SENSOR_COUNT; i++)
        {
            ProximitySensor sensor = proxSensors[i];
            float reading = sensor.read();
            uint8_t maxDistance = isExploring_p ? 200 : 50;
            if (reading > maxDistance || reading < 5)
                continue;
            int16_t absolute_orientation = (int)(heading + sensor.getOrientation()) % 360;
            double rad_angle = absolute_orientation * PI / 180.0;

            double dx_grid = (reading * cos(rad_angle)) / OBS_CELL_SIZE;
            double dy_grid = (reading * sin(rad_angle)) / OBS_CELL_SIZE;

            int gridX = (int)(x + dx_grid);
            int gridY = (int)(y + dy_grid);

            if (gridX >= 0 && gridX < OBS_GRID_SIZE && gridY >= 0 && gridY < OBS_GRID_SIZE)
            {
                obstacleGrid[gridX][gridY] = 1;
            }
        }
    }
};
#endif

ProximitySensor.h:

#ifndef PROXIMITY_SENSOR_H
#define PROXIMITY_SENSOR_H
#include <cstdint>
#include <Arduino.h>

#define SOUND_SPEED 0.0343 // m/microsec

class ProximitySensor
{
private:
    const int pin_trig;
    const int pin_echo;
    const int16_t orientation;

public:
    ProximitySensor(const int pin_trig_p, const int pin_echo_p, const int16_t orientation_p):pin_trig(pin_trig_p), pin_echo(pin_echo_p), orientation(orientation_p){}
    void setup()
    {
        Serial.println("Proximity sensor initialized with trig pin " + String(pin_trig) + " and echo pin " + String(pin_echo) + " at orientation " + String(orientation));
        pinMode(pin_trig, OUTPUT);
        pinMode(pin_echo, INPUT);
    }
    float read()
    {
        delay(10);
        Serial.println("reading prox sensor at: " + String(orientation) + " degrees");
        Serial.print("pin_trig = " + String(pin_trig) + ", pin_echo = " + String(pin_echo));
        Serial.println();
        digitalWrite(pin_trig, LOW);
        delayMicroseconds(2);
        digitalWrite(pin_trig, HIGH);
        delayMicroseconds(10);
        digitalWrite(pin_trig, LOW);

        unsigned long duration = pulseIn(pin_echo, HIGH);

        double dist = duration * SOUND_SPEED / 2;
        return (float)dist;
    }
    int16_t getOrientation() { return orientation; }
};
#endif

解决方案

你正在访问越界的数组。prox_sensors 是一个包含5 个指针的数组,每个指针都指向一个对象。然后在初始化 driveManager 时传入其中的第一个指针。在 NavigationManager::updateMapFromSensors 的每次迭代中,你把存储的指针当作指向包含5 项的数组中的第一项来访问 ProximitySensor sensor = proxSensors[i]

下面是一个最小、完整且可验证的示例(MCVE):

int main()
{
    int * array_of_pointers[3]{new int{32}, new int{45}, new int{67}};
    int * a_pointer{array_of_pointers[0]}; // a value of new int{32}
    a_pointer[0]; // ok, accessing int 32
    a_pointer[1]; // oops!
}

因此为了解决这个问题,你可以去掉所有动态分配和额外的重定向,这样传递给 NavigationManager 的指针就会实际指向这5 项中的第一项:

ProximitySensor prox_sensors[PROX_SENSOR_COUNT]
{
    ProximitySensor(23, 36, 0),
    ProximitySensor(22, 39, -25),
    ProximitySensor(19, 35, 25),
    ProximitySensor(18, 32, -120),
    ProximitySensor(21, 34, 120)
};

NavigationManager driveManager(static_cast<ProximitySensor *>(prox_sensors));

你还应该避免在每次迭代时复制 ProximitySensor 对象。改用创建一个引用。ProximitySensor & sensor{proxSensors[i]};

代码还有其他若干问题,应该去掉全局变量、C风格的类型转换、大量原始指针等。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章