Skip to content

Commit eeb4ae3

Browse files
authored
Refine tof sensor timing (#263)
* Switch to overlapping alternating measurement with timings reported by @gluap. * be more precise for the high signal timing by sending the trigger per sensor * count and expose via csv some special cases of the tof sensors * Test sensor readiness before the trigger. * Reset previously collected values in `medianMeasure` if current distance is larger. * Adjust Bluetooth and display update timings * Record measurements with next left sensor start
1 parent 3108344 commit eeb4ae3

File tree

4 files changed

+116
-32
lines changed

4 files changed

+116
-32
lines changed

src/OpenBikeSensorFirmware.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ static BluetoothManager* bluetoothManager;
6262

6363
Gps gps;
6464

65-
static const long BLUETOOTH_INTERVAL_MILLIS = 50;
65+
static const long BLUETOOTH_INTERVAL_MILLIS = 100;
6666
static long lastBluetoothInterval = 0;
6767

68-
static const long DISPLAY_INTERVAL_MILLIS = 20;
68+
static const long DISPLAY_INTERVAL_MILLIS = 25;
6969
static long lastDisplayInterval = 0;
7070

7171
float TemperatureValue = -1;
@@ -332,7 +332,7 @@ void setup() {
332332
while (!gps.hasFix(displayTest)) {
333333
currentTimeMillis = millis();
334334
gps.handle();
335-
sensorManager->pollDistancesParallel();
335+
sensorManager->pollDistancesAlternating();
336336
reportBluetooth();
337337
gps.showWaitStatus(displayTest);
338338
buttonState = digitalRead(PushButton_PIN);
@@ -357,7 +357,7 @@ void setup() {
357357
void serverLoop() {
358358
gps.handle();
359359
configServerHandle();
360-
sensorManager->pollDistancesParallel();
360+
sensorManager->pollDistancesAlternating();
361361
handleButtonInServerMode();
362362
}
363363

@@ -437,7 +437,7 @@ void loop() {
437437
loops++;
438438

439439
currentTimeMillis = millis();
440-
if (sensorManager->pollDistancesParallel()) {
440+
if (sensorManager->pollDistancesAlternating()) {
441441
// if a new minimum on the selected sensor is detected, the value and the time of detection will be stored
442442
const uint16_t reading = sensorManager->sensorValues[confirmationSensorID];
443443
if (reading > 0 && reading < minDistanceToConfirm) {

src/sensor.cpp

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ static const uint32_t MAX_TIMEOUT_MICRO_SEC = 75000;
5656
/* To avoid that we receive a echo from a former measurement, we do not
5757
* start a new measurement within the given time from the start of the
5858
* former measurement of the opposite sensor.
59+
* High values can lead to the situation that we only poll the
60+
* primary sensor for a while!?
5961
*/
60-
static const uint32_t SENSOR_QUIET_PERIOD_AFTER_OPPOSITE_START_MICRO_SEC = 50 * 1000;
62+
static const uint32_t SENSOR_QUIET_PERIOD_AFTER_OPPOSITE_START_MICRO_SEC = 30 * 1000;
6163

6264
/* The last end (echo goes to low) of a measurement must be this far
6365
* away before a new measurement is started.
@@ -70,7 +72,7 @@ static const uint32_t SENSOR_QUIET_PERIOD_AFTER_END_MICRO_SEC = 10 * 1000;
7072
- With 30ms I could get stable readings down to 25/35cm only (new sensor)
7173
- It looked fine with the old sensor for all values
7274
*/
73-
static const uint32_t SENSOR_QUIET_PERIOD_AFTER_START_MICRO_SEC = 30 * 1000;
75+
static const uint32_t SENSOR_QUIET_PERIOD_AFTER_START_MICRO_SEC = 35 * 1000;
7476

7577
/* Value of HCSR04SensorInfo::end during an ongoing measurement. */
7678
static const uint32_t MEASUREMENT_IN_PROGRESS = 0;
@@ -177,6 +179,7 @@ void HCSR04SensorManager::reset() {
177179
sensor.numberOfTriggers = 0;
178180
}
179181
lastReadingCount = 0;
182+
lastSensor = 1 - primarySensor;
180183
memset(&(startOffsetMilliseconds), 0, sizeof(startOffsetMilliseconds));
181184
startReadingMilliseconds = millis();
182185
}
@@ -198,6 +201,24 @@ void HCSR04SensorManager::setPrimarySensor(uint8_t idx) {
198201
primarySensor = idx;
199202
}
200203

204+
/* Polls for new readings, if sensors are not ready, the
205+
* method returns false.
206+
*/
207+
bool HCSR04SensorManager::pollDistancesAlternating() {
208+
bool newMeasurements = false;
209+
if (lastSensor == primarySensor && isReadyForStart(1 - primarySensor)) {
210+
setSensorTriggersToLow();
211+
lastSensor = 1 - primarySensor;
212+
sendTriggerToSensor(1 - primarySensor);
213+
} else if (isReadyForStart(primarySensor)) {
214+
newMeasurements = collectSensorResults();
215+
setSensorTriggersToLow();
216+
lastSensor = primarySensor;
217+
sendTriggerToSensor(primarySensor);
218+
}
219+
return newMeasurements;
220+
}
221+
201222
/* Polls for new readings, if sensors are not ready, the
202223
* method returns false. If sensors are ready and readings
203224
* are available, data is read and updated. If the primary
@@ -210,12 +231,11 @@ bool HCSR04SensorManager::pollDistancesParallel() {
210231
if (isReadyForStart(primarySensor)) {
211232
setSensorTriggersToLow();
212233
newMeasurements = collectSensorResults();
213-
if (isReadyForStart(1 - primarySensor)) {
234+
const bool secondSensorIsReady = isReadyForStart(1 - primarySensor);
235+
sendTriggerToSensor(primarySensor);
236+
if (secondSensorIsReady) {
214237
sendTriggerToSensor(1 - primarySensor);
215238
}
216-
sendTriggerToSensor(primarySensor);
217-
delayMicroseconds(20);
218-
setSensorTriggersToLow();
219239
}
220240
return newMeasurements;
221241
}
@@ -231,16 +251,20 @@ void HCSR04SensorManager::sendTriggerToSensor(uint8_t sensorId) {
231251
HCSR04SensorInfo * const sensor = &(m_sensors[sensorId]);
232252
updateStatistics(sensor);
233253
sensor->end = MEASUREMENT_IN_PROGRESS; // will be updated with LOW signal
234-
sensor->trigger = sensor->start = micros(); // will be updated with HIGH signal
235254
sensor->numberOfTriggers++;
236255
sensor->measurementRead = false;
256+
sensor->trigger = sensor->start = micros(); // will be updated with HIGH signal
237257
digitalWrite(sensor->triggerPin, HIGH);
258+
// 10us are specified but some sensors are more stable with 20us according
259+
// to internet reports
260+
delayMicroseconds(20);
261+
digitalWrite(sensor->triggerPin, LOW);
238262
}
239263

240264
/* Checks if the given sensor is ready for a new measurement cycle.
241265
*/
242266
boolean HCSR04SensorManager::isReadyForStart(uint8_t sensorId) {
243-
const HCSR04SensorInfo * const sensor = &m_sensors[sensorId];
267+
HCSR04SensorInfo * const sensor = &m_sensors[sensorId];
244268
boolean ready = false;
245269
const uint32_t now = micros();
246270
const uint32_t start = sensor->start;
@@ -254,10 +278,10 @@ boolean HCSR04SensorManager::isReadyForStart(uint8_t sensorId) {
254278
}
255279
if (digitalRead(sensor->echoPin) != LOW) {
256280
log_e("Measurement done, but echo pin is high for %s sensor", sensor->sensorLocation);
281+
sensor->numberOfLowAfterMeasurement++;
257282
}
258-
259-
260-
} else if (microsBetween(now, start) > 2 * MAX_TIMEOUT_MICRO_SEC) {
283+
} else if (microsBetween(now, start) > MAX_TIMEOUT_MICRO_SEC) {
284+
sensor->numberOfToLongMeasurement++;
261285
// signal or interrupt was lost altogether this is an error,
262286
// should we raise it?? Now pretend the sensor is ready, hope it helps to give it a trigger.
263287
ready = true;
@@ -329,7 +353,6 @@ bool HCSR04SensorManager::collectSensorResult(uint8_t sensorId) {
329353

330354
if (sensor->distance > 0 && sensor->distance < sensor->minDistance) {
331355
sensor->minDistance = sensor->distance;
332-
sensor->lastMinUpdate = millis();
333356
}
334357
sensor->measurementRead = true;
335358
return validReading;
@@ -355,25 +378,35 @@ uint32_t HCSR04SensorManager::getNoSignalReadings(const uint8_t sensorId) {
355378
return m_sensors[sensorId].numberOfNoSignals;
356379
}
357380

381+
uint32_t HCSR04SensorManager::getNumberOfLowAfterMeasurement(const uint8_t sensorId) {
382+
return m_sensors[sensorId].numberOfLowAfterMeasurement;
383+
}
384+
385+
uint32_t HCSR04SensorManager::getNumberOfToLongMeasurement(const uint8_t sensorId) {
386+
return m_sensors[sensorId].numberOfToLongMeasurement;
387+
}
388+
389+
uint32_t HCSR04SensorManager::getNumberOfInterruptAdjustments(const uint8_t sensorId) {
390+
return m_sensors[sensorId].numberOfInterruptAdjustments;
391+
}
392+
358393
/* During debugging I observed readings that did not get `start` updated
359394
* By the interrupt. Since we also set start when we send the pulse to the
360395
* sensor this adds 300 microseconds or 5 centimeters to the measured result.
361396
* After research, is a bug in the ESP!? See https://esp32.com/viewtopic.php?t=10124
362397
*/
363398
uint32_t HCSR04SensorManager::getFixedStart(
364-
size_t idx, const HCSR04SensorInfo * const sensor) {
399+
size_t idx, HCSR04SensorInfo * const sensor) {
365400
uint32_t start = sensor->start;
366401
// the error appears if both sensors trigger the interrupt at the exact same
367402
// time, if this happens, trigger time == start time
368-
if (sensor->trigger == sensor->start) {
369-
for (size_t idx2 = 0; idx2 < NUMBER_OF_TOF_SENSORS; ++idx2) {
370-
if (idx2 != idx) {
371-
// it should be save to use the start value from the other sensor.
372-
const uint32_t alternativeStart = m_sensors[idx2].start;
373-
if (microsBetween(alternativeStart, start) < 500) { // typically 290-310 microseconds {
374-
start = alternativeStart;
375-
}
376-
}
403+
if (start == sensor->trigger && sensor->end != MEASUREMENT_IN_PROGRESS) {
404+
// it should be save to use the start value from the other sensor.
405+
const uint32_t alternativeStart = m_sensors[1 - idx].start;
406+
if (alternativeStart != m_sensors[1 - idx].trigger
407+
&& microsBetween(alternativeStart, start) < 500) { // typically 290-310 microseconds {
408+
start = alternativeStart;
409+
sensor->numberOfInterruptAdjustments++;
377410
}
378411
}
379412
return start;
@@ -450,6 +483,14 @@ uint16_t HCSR04SensorManager::millisSince(uint16_t milliseconds) {
450483
uint16_t HCSR04SensorManager::medianMeasure(HCSR04SensorInfo *const sensor, uint16_t value) {
451484
sensor->distances[sensor->nextMedianDistance] = value;
452485
sensor->nextMedianDistance++;
486+
487+
// if we got "fantom" measures, they are <= the current measures, so remove
488+
// all values <= the current measure from the median data
489+
for (unsigned short & distance : sensor->distances) {
490+
if (distance < value) {
491+
distance = value;
492+
}
493+
}
453494
if (sensor->nextMedianDistance >= MEDIAN_DISTANCE_MEASURES) {
454495
sensor->nextMedianDistance = 0;
455496
}

src/sensor.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const uint32_t MICRO_SEC_TO_CM_DIVIDER = 58; // sound speed 340M/S, 2 times back
5353

5454

5555
const uint16_t MEDIAN_DISTANCE_MEASURES = 3;
56-
const uint16_t MAX_NUMBER_MEASUREMENTS_PER_INTERVAL = 35; // is 1000/SENSOR_QUIET_PERIOD_AFTER_START_MICRO_SEC
56+
const uint16_t MAX_NUMBER_MEASUREMENTS_PER_INTERVAL = 30; // is 1000/SENSOR_QUIET_PERIOD_AFTER_START_MICRO_SEC/2
5757
extern const uint16_t MAX_SENSOR_VALUE;
5858

5959
const uint8_t NUMBER_OF_TOF_SENSORS = 2;
@@ -68,7 +68,6 @@ struct HCSR04SensorInfo {
6868
uint16_t minDistance = MAX_SENSOR_VALUE;
6969
uint16_t distance = MAX_SENSOR_VALUE;
7070
char* sensorLocation;
71-
unsigned long lastMinUpdate=0;
7271
// timestamp when the trigger signal was sent in us micros()
7372
uint32_t trigger = 0;
7473
volatile uint32_t start = 0;
@@ -84,6 +83,9 @@ struct HCSR04SensorInfo {
8483
// counts how often no echo and also no timeout signal was received
8584
// should only happen with defect or missing sensors
8685
uint32_t numberOfNoSignals = 0;
86+
uint32_t numberOfLowAfterMeasurement = 0;
87+
uint32_t numberOfToLongMeasurement = 0;
88+
uint32_t numberOfInterruptAdjustments = 0;
8789
uint16_t numberOfTriggers = 0;
8890
bool measurementRead;
8991
};
@@ -108,12 +110,16 @@ class HCSR04SensorManager {
108110
uint32_t getMinDurationUs(uint8_t sensorId);
109111
uint32_t getLastDelayTillStartUs(uint8_t sensorId);
110112
uint32_t getNoSignalReadings(const uint8_t sensorId);
113+
uint32_t getNumberOfLowAfterMeasurement(const uint8_t sensorId);
114+
uint32_t getNumberOfToLongMeasurement(const uint8_t sensorId);
115+
uint32_t getNumberOfInterruptAdjustments(const uint8_t sensorId);
111116

112117
HCSR04SensorInfo m_sensors[NUMBER_OF_TOF_SENSORS];
113118
uint16_t sensorValues[NUMBER_OF_TOF_SENSORS];
114119
uint16_t lastReadingCount = 0;
115120
uint16_t startOffsetMilliseconds[MAX_NUMBER_MEASUREMENTS_PER_INTERVAL + 1];
116121
bool pollDistancesParallel();
122+
bool pollDistancesAlternating();
117123

118124
protected:
119125

@@ -123,7 +129,7 @@ class HCSR04SensorManager {
123129
void setSensorTriggersToLow();
124130
bool collectSensorResults();
125131
void attachSensorInterrupt(uint8_t idx);
126-
uint32_t getFixedStart(size_t idx, const HCSR04SensorInfo * const sensor);
132+
uint32_t getFixedStart(size_t idx, HCSR04SensorInfo * const sensor);
127133
boolean isReadyForStart(uint8_t sensorId);
128134
void registerReadings();
129135
static uint16_t medianMeasure(HCSR04SensorInfo* const sensor, uint16_t value);
@@ -135,6 +141,7 @@ class HCSR04SensorManager {
135141
static void updateStatistics(HCSR04SensorInfo * const sensor);
136142
uint16_t startReadingMilliseconds = 0;
137143
uint8_t primarySensor = 1;
144+
uint8_t lastSensor;
138145
};
139146

140147
#endif

src/writer.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,44 @@ bool CSVFileWriter::append(DataSet &set) {
229229
} else if (time.tm_sec == 7) {
230230
csv += "DEV: Right Sensor no : ";
231231
csv += sensorManager->getNoSignalReadings(RIGHT_SENSOR_ID);
232-
} else if (time.tm_sec >= 8 && time.tm_sec < 28) {
233-
String msg = gps.getMessage(time.tm_sec - 8);
232+
} else if (time.tm_sec == 8) {
233+
csv += "DEV: Left last delay till start : ";
234+
csv += sensorManager->getLastDelayTillStartUs(LEFT_SENSOR_ID);
235+
} else if (time.tm_sec == 9) {
236+
csv += "DEV: Right last delay till start : ";
237+
csv += sensorManager->getLastDelayTillStartUs(RIGHT_SENSOR_ID);
238+
} else if (time.tm_sec == 10) {
239+
csv += "DEV: Left min echo : ";
240+
csv += sensorManager->getMinDurationUs(LEFT_SENSOR_ID);
241+
} else if (time.tm_sec == 11) {
242+
csv += "DEV: Right min echo : ";
243+
csv += sensorManager->getMinDurationUs(RIGHT_SENSOR_ID);
244+
} else if (time.tm_sec == 12) {
245+
csv += "DEV: Left max echo : ";
246+
csv += sensorManager->getMaxDurationUs(LEFT_SENSOR_ID);
247+
} else if (time.tm_sec == 13) {
248+
csv += "DEV: Right max echo : ";
249+
csv += sensorManager->getMaxDurationUs(RIGHT_SENSOR_ID);
250+
} else if (time.tm_sec == 14) {
251+
csv += "DEV: Left low after measure: ";
252+
csv += sensorManager->getNumberOfLowAfterMeasurement(LEFT_SENSOR_ID);
253+
} else if (time.tm_sec == 15) {
254+
csv += "DEV: Right low after measure : ";
255+
csv += sensorManager->getNumberOfLowAfterMeasurement(RIGHT_SENSOR_ID);
256+
} else if (time.tm_sec == 16) {
257+
csv += "DEV: Left long measurement : ";
258+
csv += sensorManager->getNumberOfToLongMeasurement(LEFT_SENSOR_ID);
259+
} else if (time.tm_sec == 17) {
260+
csv += "DEV: Right long measurement : ";
261+
csv += sensorManager->getNumberOfToLongMeasurement(RIGHT_SENSOR_ID);
262+
} else if (time.tm_sec == 18) {
263+
csv += "DEV: Left interrupt adjusted : ";
264+
csv += sensorManager->getNumberOfInterruptAdjustments(LEFT_SENSOR_ID);
265+
} else if (time.tm_sec == 19) {
266+
csv += "DEV: Right interrupt adjusted : ";
267+
csv += sensorManager->getNumberOfInterruptAdjustments(RIGHT_SENSOR_ID);
268+
} else if (time.tm_sec >= 20 && time.tm_sec < 40) {
269+
String msg = gps.getMessage(time.tm_sec - 20);
234270
if (!msg.isEmpty()) {
235271
csv += "DEV: GPS: ";
236272
csv += ObsUtils::encodeForCsvField(msg);

0 commit comments

Comments
 (0)