在ESP32的 C++中损坏对象变量
我正在为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风格的类型转换、大量原始指针等。