From cb7357d28764a25f2eff202fd8e1184871a7602b Mon Sep 17 00:00:00 2001 From: mitko Date: Wed, 15 Jun 2022 17:49:40 +0200 Subject: [PATCH 01/21] Remove redundant files. --- utils/DiodeVisualiser/cpp_matplotlib.cpp | 7 ---- utils/DiodeVisualiser/main.cpp | 45 ------------------------ 2 files changed, 52 deletions(-) delete mode 100644 utils/DiodeVisualiser/cpp_matplotlib.cpp delete mode 100644 utils/DiodeVisualiser/main.cpp diff --git a/utils/DiodeVisualiser/cpp_matplotlib.cpp b/utils/DiodeVisualiser/cpp_matplotlib.cpp deleted file mode 100644 index 2fae753..0000000 --- a/utils/DiodeVisualiser/cpp_matplotlib.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "matplotlibcpp.h" -namespace plt = matplotlibcpp; -int main() { - - plt::plot({1,3,2,4}); - plt::show(); -} \ No newline at end of file diff --git a/utils/DiodeVisualiser/main.cpp b/utils/DiodeVisualiser/main.cpp deleted file mode 100644 index 457e7c1..0000000 --- a/utils/DiodeVisualiser/main.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include - -#define SCREEN_WIDTH 128 // OLED display width, in pixels -#define SCREEN_HEIGHT 64 // OLED display height, in pixels -#define OLED_ADDRESS 0x3C -Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); -int vals[128]; - -void setup() { - pinMode(A0, INPUT); - pinMode(A1, INPUT); - - Serial.begin(9600); - - // Init display - if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) { // Address 0x3D for 128x64 - Serial.println(F("SSD1306 allocation failed")); - for(;;); - } - delay(2000); - - for (int i = 0; i < 128; i++) { - vals[i] = analogRead(A1) / 15; - delay(5); - } -} - -void loop() { - display.clearDisplay(); - - int val = analogRead(A1) / 15; - - for (int i = 0; i < 127; i++) { - vals[i] = vals[i+1]; - } - vals[127] = val; - - for (int i = 0; i < 128; i++) { - display.drawLine(i, 0, i, vals[i], WHITE); - } - - display.display(); -} \ No newline at end of file From 3ea1663e69849495c74c4818c5aab52819c81e27 Mon Sep 17 00:00:00 2001 From: mitko Date: Thu, 16 Jun 2022 11:30:58 +0200 Subject: [PATCH 02/21] Receiver: Refactor into Finite State Machine. --- src/receiver/receiver.hpp | 292 +++++++++++++++++++++++--------------- 1 file changed, 174 insertions(+), 118 deletions(-) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 84cc8fd..cd476d2 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -13,181 +13,237 @@ #include "../ml-arduino/prediction_enums.hpp" #include "../ml-arduino/main_arduino.hpp" +enum class State +{ + INITIALISING, + DETECTING_START, + DETECTING_END, + UPDATING_THRESHOLD, + RESETTING +}; + +State state = State::INITIALISING; + int count = 0; bool detectionWindowFull = false; +bool endDetected = false; // Buffers for dynamic threshold adjustment uint16_t thresholdAdjustmentBuffer[NUM_PDs][THRESHOLD_ADJ_BUFFER_LENGTH]; -uint16_t * taBuffer[NUM_PDs]; +uint16_t *taBuffer[NUM_PDs]; // Buffers for gesture signal capture uint16_t photodiodeData[NUM_PDs][GESTURE_BUFFER_LENGTH]; -uint16_t * photodiodeDataPtr[NUM_PDs]; +uint16_t *photodiodeDataPtr[NUM_PDs]; int gestureSignalLength; -GRDiodeReader reader; -GREdgeDetector edgeDetector[NUM_PDs]; -GRPreprocessingPipeline pipeline; +GRDiodeReader reader; +GREdgeDetector edgeDetector[NUM_PDs]; +GRPreprocessingPipeline pipeline; SimpleTimer timer; int timID; +void receiverOperationUpdateThreshold() +{ + for (size_t i = 0; i < NUM_PDs; i++) + { + uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_ADJ_BUFFER_LENGTH); + edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); + edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); + taBuffer[i] = thresholdAdjustmentBuffer[i]; + } -void receiverLoopMain() { - if(detectionWindowFull == false) { - // If the detection window is not filled, fill it - for (size_t i = 0; i < NUM_PDs; i++) - { - reader.read(pds[i], photodiodeDataPtr[i]++); - reader.read(pds[i], taBuffer[i]++); - } - - count++; - - if (count == DETECTION_BUFFER_LENGTH) { - for (size_t i = 0; i < NUM_PDs; i++) photodiodeDataPtr[i]--; - detectionWindowFull = true; - } + state = State::DETECTING_START; +} - } else { +void receiverOperationInitialising() +{ + // If the detection window is not filled, fill it + for (size_t i = 0; i < NUM_PDs; i++) + { + reader.read(pds[i], photodiodeDataPtr[i]++); + reader.read(pds[i], taBuffer[i]++); + } + count++; + if (count == DETECTION_BUFFER_LENGTH) + { + for (size_t i = 0; i < NUM_PDs; i++) + photodiodeDataPtr[i]--; + state = State::DETECTING_START; + } +} - // If the detection window is already filled, shift it left with 1 - // and put the new sample in the last place - for (size_t i = 0; i < DETECTION_BUFFER_LENGTH - 1; i++) - for (size_t pdId = 0; pdId < NUM_PDs; pdId++) - photodiodeData[pdId][i] = photodiodeData[pdId][i+1]; +void receiverOperationDetectingStart() +{ + // If the detection window is already filled, shift it left with 1 + // and put the new sample in the last place + FOR(di, i, NUM_PDs, DETECTION_BUFFER_LENGTH - 1, photodiodeData[di][i] = photodiodeData[di][i + 1]) - for (size_t i = 0; i < NUM_PDs; i++) - { - reader.read(pds[i], photodiodeDataPtr[i]); - reader.read(pds[i], taBuffer[i]++); - } + for (size_t i = 0; i < NUM_PDs; i++) + { + reader.read(pds[i], photodiodeDataPtr[i]); + reader.read(pds[i], taBuffer[i]++); } // If there was no gesture recently, update the threshold - if (taBuffer[0] - thresholdAdjustmentBuffer[0] >= THRESHOLD_ADJ_BUFFER_LENGTH) { - - for (size_t i = 0; i < NUM_PDs; i++) - { - uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_ADJ_BUFFER_LENGTH); - edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); - edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); - taBuffer[i] = thresholdAdjustmentBuffer[i]; - } + if (taBuffer[0] - thresholdAdjustmentBuffer[0] >= THRESHOLD_ADJ_BUFFER_LENGTH) + { + state = State::UPDATING_THRESHOLD; + return; } + // Try to detect a start on one of the photodiodes bool startEdgeDetected = false; - for (size_t i = 0; i < NUM_PDs; i++) + for (size_t i = 0; i < NUM_PDs; i++) startEdgeDetected = startEdgeDetected || edgeDetector[i].DetectStart(photodiodeDataPtr[i]); - - // Try to detect a start on one of the photodiodes - if (detectionWindowFull && startEdgeDetected) { - #ifdef DEBUG_RECEIVER + if (detectionWindowFull && startEdgeDetected) + { + state = State::DETECTING_END; + #ifdef DEBUG_RECEIVER Serial.println("Gesture started"); #endif + } +} - bool endDetected = false; +void receiverOperationDetectingEnd() +{ + // Read enough more data to avoid buffer overflow when checking end + // of gesture if more samples are checked for end than for start + if (count++ < DETECTION_END_WINDOW_LENGTH - DETECTION_BUFFER_LENGTH) + { + for (size_t i = 0; i < NUM_PDs; i++) + { + photodiodeDataPtr[i]++; + reader.read(pds[i], photodiodeDataPtr[i]); + } + return; + } - // Read enough more data to avoid buffer overflow when checking end - // of gesture if more samples are checked for end than for start - while(count++ < DETECTION_END_WINDOW_LENGTH - DETECTION_BUFFER_LENGTH) { - for (size_t i = 0; i < NUM_PDs; i++) - { - photodiodeDataPtr[i]++; - reader.read(pds[i], photodiodeDataPtr[i]); - } - delay(READ_PERIOD); + // Read new data and check for end of gesture + if (count++ < GESTURE_BUFFER_LENGTH) + { + // Read next sample + for (size_t i = 0; i < NUM_PDs; i++) + { + photodiodeDataPtr[i]++; + reader.read(pds[i], photodiodeDataPtr[i]); } - // Read new data and check for end of gesture - while(count++ < GESTURE_BUFFER_LENGTH) { - for (size_t i = 0; i < NUM_PDs; i++) + // Try to detect end in all photodiodes + bool endEdgeDetected = true; + for (size_t i = 0; i < NUM_PDs; i++) + endEdgeDetected = endEdgeDetected && edgeDetector[i].DetectEnd(photodiodeDataPtr[i]); + + if (endEdgeDetected) + { + // Determine the gesture length + gestureSignalLength = photodiodeDataPtr[0] - photodiodeData[0] + 1; + + // Reject gestures that took too short time + if (gestureSignalLength < GESTURE_MIN_TIME_MS / READ_PERIOD + 1) { - photodiodeDataPtr[i]++; - reader.read(pds[i], photodiodeDataPtr[i]); + #ifdef DEBUG_RECEIVER + Serial.println("Gesture took too little time! Rejecting and starting over ..."); + #endif + state = State::RESETTING; + timer.restartTimer(timID); + } + else { + endDetected = true; } - delay(READ_PERIOD); + // ------------------------------------------ + // Run the pipeline + uint16_t thresholds[NUM_PDs]; - bool endEdgeDetected = true; for (size_t i = 0; i < NUM_PDs; i++) - endEdgeDetected = endEdgeDetected && edgeDetector[i].DetectEnd(photodiodeDataPtr[i]); - - if(endEdgeDetected) { + { + thresholds[i] = edgeDetector[i].getCutOffThreshold(); + } - // Determine the gesture length - gestureSignalLength = photodiodeDataPtr[0] - photodiodeData[0] + 1; + pipeline.RunPipeline(photodiodeData, gestureSignalLength, thresholds); - // Reject gestures that took too short time - if (gestureSignalLength < GESTURE_MIN_TIME_MS / READ_PERIOD + 1) { - - #ifdef DEBUG_RECEIVER - Serial.println("Gesture took too little time! Rejecting and starting over ..."); - #endif - - break; - } - else endDetected = true; + float(*output)[100] = pipeline.getPipelineOutput(); - // ------------------------------------------ - // Run the pipeline + Gesture g = inferGesture2d(output); - uint16_t thresholds[NUM_PDs]; - for (size_t i = 0; i < NUM_PDs; i++) - { - thresholds[i] = edgeDetector[i].getCutOffThreshold(); - } + Serial.print("Gesture: "); + Serial.println(g); - pipeline.RunPipeline(photodiodeData, gestureSignalLength, thresholds); + state = State::RESETTING; + timer.restartTimer(timID); + } + } else { + // Gesture took too long -> Light Intensity Change -> Threshold Recalculation + state = State::UPDATING_THRESHOLD; + timer.restartTimer(timID); + } +} - float (* output)[100] = pipeline.getPipelineOutput(); +void receiverOperationResetting() +{ + // Reset the buffer pointers for PD gesture data collection + detectionWindowFull = false; + for (size_t i = 0; i < NUM_PDs; i++) + { + photodiodeDataPtr[i] = photodiodeData[i]; + taBuffer[i] = thresholdAdjustmentBuffer[i]; + } + + if (!endDetected) { + state = State::UPDATING_THRESHOLD; + } else { + state = State::INITIALISING; + } + timer.restartTimer(timID); +} - Gesture g = inferGesture2d(output); - - Serial.print("Gesture: "); - Serial.println(g); +void receiverRunOperation() +{ + switch (state) + { + case State::INITIALISING: + receiverOperationInitialising(); + break; - break; - } - } + case State::DETECTING_START: + receiverOperationDetectingStart(); + break; - // Reset the buffer pointers for PD gesture data collection - detectionWindowFull = false; - for (size_t i = 0; i < NUM_PDs; i++) - { - photodiodeDataPtr[i] = photodiodeData[i]; - taBuffer[i] = thresholdAdjustmentBuffer[i]; - } + case State::DETECTING_END: + receiverOperationDetectingEnd(); + break; - count = 0; + case State::UPDATING_THRESHOLD: + receiverOperationUpdateThreshold(); + break; - // Gesture took too long -> Light Intensity Change -> Threshold Recalculation - if(!endDetected) - for (size_t i = 0; i < NUM_PDs; i++) { - uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_ADJ_BUFFER_LENGTH); - edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); - edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); - } + case State::RESETTING: + receiverOperationResetting(); + break; - timer.restartTimer(timID); + default: + break; } } -void receiverSetup() { +void receiverSetup() +{ for (size_t i = 0; i < NUM_PDs; i++) { pinMode(pds[i], INPUT); - taBuffer[i] = thresholdAdjustmentBuffer[i]; - photodiodeDataPtr[i] = photodiodeData[i]; - edgeDetector[i] = GREdgeDetector(DETECTION_WINDOW_LENGTH, DETECTION_END_WINDOW_LENGTH, 750); + taBuffer[i] = thresholdAdjustmentBuffer[i]; + photodiodeDataPtr[i] = photodiodeData[i]; + edgeDetector[i] = GREdgeDetector(DETECTION_WINDOW_LENGTH, DETECTION_END_WINDOW_LENGTH, 750); } Serial.begin(9600); - - timID = timer.setInterval(READ_PERIOD, receiverLoopMain); + timID = timer.setInterval(READ_PERIOD, receiverRunOperation); } -void receiverLoop() { - timer.run(); -} +void receiverLoop() +{ + timer.run(); +} \ No newline at end of file From cb3922a8b1325f1ba8b2a2be7bb169c8cd13955a Mon Sep 17 00:00:00 2001 From: mitko Date: Thu, 16 Jun 2022 11:40:39 +0200 Subject: [PATCH 03/21] Receiver: Add LI regulator. --- src/receiver/receiver.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index cd476d2..283c1cb 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -13,6 +13,8 @@ #include "../ml-arduino/prediction_enums.hpp" #include "../ml-arduino/main_arduino.hpp" +#include "../diode_calibration/diode_calibration.h" + enum class State { INITIALISING, @@ -44,6 +46,8 @@ GRPreprocessingPipeline pipeline; SimpleTimer timer; int timID; +LightIntensityRegulator regulator; + void receiverOperationUpdateThreshold() { for (size_t i = 0; i < NUM_PDs; i++) From 5cd32b577207d9c4e1a9439cbb3abea0c5a1415d Mon Sep 17 00:00:00 2001 From: mitko Date: Thu, 16 Jun 2022 11:56:26 +0200 Subject: [PATCH 04/21] Receiver: Use LI regulator. --- src/receiver/receiver-parameters.h | 1 + src/receiver/receiver.hpp | 78 ++++++++++++++++++++++++------ 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/receiver/receiver-parameters.h b/src/receiver/receiver-parameters.h index ad7cf99..6ee84ba 100644 --- a/src/receiver/receiver-parameters.h +++ b/src/receiver/receiver-parameters.h @@ -23,6 +23,7 @@ #define GESTURE_BUFFER_LENGTH 500 // Buffer for threshold adjustment #define THRESHOLD_ADJ_BUFFER_LENGTH 100 +#define THRESHOLD_UPD_BUFFER_LENGTH 20 // Sampling period and minimum expected gesture duration #define READ_PERIOD 10 diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 283c1cb..199fc78 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -21,18 +21,21 @@ enum class State DETECTING_START, DETECTING_END, UPDATING_THRESHOLD, + UPDATING_THRESHOLD_ACTUAL, RESETTING }; State state = State::INITIALISING; int count = 0; +int threshUpdateCount = 0; bool detectionWindowFull = false; bool endDetected = false; // Buffers for dynamic threshold adjustment uint16_t thresholdAdjustmentBuffer[NUM_PDs][THRESHOLD_ADJ_BUFFER_LENGTH]; uint16_t *taBuffer[NUM_PDs]; +uint16_t thresholdUpdateBuffer[NUM_PDs][THRESHOLD_UPD_BUFFER_LENGTH]; // Buffers for gesture signal capture uint16_t photodiodeData[NUM_PDs][GESTURE_BUFFER_LENGTH]; @@ -48,17 +51,50 @@ int timID; LightIntensityRegulator regulator; +void receiverOperationUpdateThresholdActual() { + if (threshUpdateCount < THRESHOLD_UPD_BUFFER_LENGTH) { + for (size_t i = 0; i < NUM_PDs; i++) + { + reader.read(pds[i], thresholdUpdateBuffer[i] + threshUpdateCount); + } + threshUpdateCount++; + } else { + threshUpdateCount = 0; + for (size_t i = 0; i < NUM_PDs; i++) + { + uint16_t stable = QuickMedian::GetMedian(thresholdUpdateBuffer[i], THRESHOLD_UPD_BUFFER_LENGTH); + edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); + edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); + } + + state = State::DETECTING_START; + } +} + void receiverOperationUpdateThreshold() { + bool deltaLBigger = false, deltaLSmaller = false; + for (size_t i = 0; i < NUM_PDs; i++) { uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_ADJ_BUFFER_LENGTH); - edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); - edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); + uint16_t deltaL = stable * DETECTION_THRESHOLD_COEFF - edgeDetector[i].getThreshold(); + + if (deltaL > 100) + deltaLBigger = true; + if (deltaL < -100) + deltaLSmaller = true; + taBuffer[i] = thresholdAdjustmentBuffer[i]; } - state = State::DETECTING_START; + if (deltaLBigger) + regulator.resistorDown(); + else if (deltaLSmaller) + regulator.resistorUp(); + + // Calculate new threshold + state = State::UPDATING_THRESHOLD_ACTUAL; } void receiverOperationInitialising() @@ -105,9 +141,9 @@ void receiverOperationDetectingStart() if (detectionWindowFull && startEdgeDetected) { state = State::DETECTING_END; - #ifdef DEBUG_RECEIVER - Serial.println("Gesture started"); - #endif +#ifdef DEBUG_RECEIVER + Serial.println("Gesture started"); +#endif } } @@ -144,17 +180,18 @@ void receiverOperationDetectingEnd() { // Determine the gesture length gestureSignalLength = photodiodeDataPtr[0] - photodiodeData[0] + 1; - + // Reject gestures that took too short time if (gestureSignalLength < GESTURE_MIN_TIME_MS / READ_PERIOD + 1) { - #ifdef DEBUG_RECEIVER - Serial.println("Gesture took too little time! Rejecting and starting over ..."); - #endif +#ifdef DEBUG_RECEIVER + Serial.println("Gesture took too little time! Rejecting and starting over ..."); +#endif state = State::RESETTING; timer.restartTimer(timID); } - else { + else + { endDetected = true; } @@ -179,8 +216,10 @@ void receiverOperationDetectingEnd() state = State::RESETTING; timer.restartTimer(timID); } - } else { - // Gesture took too long -> Light Intensity Change -> Threshold Recalculation + } + else + { + // Gesture took too long -> Light Intensity Change -> Threshold Recalculation state = State::UPDATING_THRESHOLD; timer.restartTimer(timID); } @@ -195,10 +234,13 @@ void receiverOperationResetting() photodiodeDataPtr[i] = photodiodeData[i]; taBuffer[i] = thresholdAdjustmentBuffer[i]; } - - if (!endDetected) { + + if (!endDetected) + { state = State::UPDATING_THRESHOLD; - } else { + } + else + { state = State::INITIALISING; } timer.restartTimer(timID); @@ -224,6 +266,10 @@ void receiverRunOperation() receiverOperationUpdateThreshold(); break; + case State::UPDATING_THRESHOLD_ACTUAL: + receiverOperationUpdateThresholdActual(); + break; + case State::RESETTING: receiverOperationResetting(); break; From 2261e9bf48480a8a466c3f8edf1c43309845840c Mon Sep 17 00:00:00 2001 From: mitko Date: Thu, 16 Jun 2022 13:04:49 +0200 Subject: [PATCH 05/21] Receiver: Divide threshold adjustment into 2 states. --- src/receiver/receiver.hpp | 82 +++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 199fc78..5c86284 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -20,7 +20,8 @@ enum class State INITIALISING, DETECTING_START, DETECTING_END, - UPDATING_THRESHOLD, + UPDATING_THRESHOLD_AB, + UPDATING_THRESHOLD_PB, UPDATING_THRESHOLD_ACTUAL, RESETTING }; @@ -51,27 +52,30 @@ int timID; LightIntensityRegulator regulator; -void receiverOperationUpdateThresholdActual() { - if (threshUpdateCount < THRESHOLD_UPD_BUFFER_LENGTH) { - for (size_t i = 0; i < NUM_PDs; i++) - { - reader.read(pds[i], thresholdUpdateBuffer[i] + threshUpdateCount); - } - threshUpdateCount++; - } else { - threshUpdateCount = 0; - for (size_t i = 0; i < NUM_PDs; i++) - { - uint16_t stable = QuickMedian::GetMedian(thresholdUpdateBuffer[i], THRESHOLD_UPD_BUFFER_LENGTH); - edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); - edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); - } +void receiverOperationUpdateThresholdFromPhoBuffer() { + bool deltaLBigger = false, deltaLSmaller = false; - state = State::DETECTING_START; + for (size_t i = 0; i < NUM_PDs; i++) + { + uint16_t stable = QuickMedian::GetMedian(photodiodeData[i], GESTURE_BUFFER_LENGTH); + uint16_t deltaL = stable * DETECTION_THRESHOLD_COEFF - edgeDetector[i].getThreshold(); + + if (deltaL > 100) + deltaLBigger = true; + if (deltaL < -100) + deltaLSmaller = true; } + + if (deltaLBigger) + regulator.resistorDown(); + else if (deltaLSmaller) + regulator.resistorUp(); + + // Calculate new threshold + state = State::UPDATING_THRESHOLD_ACTUAL; } -void receiverOperationUpdateThreshold() +void receiverOperationUpdateThresholdFromAdjBuffer() { bool deltaLBigger = false, deltaLSmaller = false; @@ -97,6 +101,26 @@ void receiverOperationUpdateThreshold() state = State::UPDATING_THRESHOLD_ACTUAL; } +void receiverOperationUpdateThresholdActual() { + if (threshUpdateCount < THRESHOLD_UPD_BUFFER_LENGTH) { + for (size_t i = 0; i < NUM_PDs; i++) + { + reader.read(pds[i], thresholdUpdateBuffer[i] + threshUpdateCount); + } + threshUpdateCount++; + } else { + threshUpdateCount = 0; + for (size_t i = 0; i < NUM_PDs; i++) + { + uint16_t stable = QuickMedian::GetMedian(thresholdUpdateBuffer[i], THRESHOLD_UPD_BUFFER_LENGTH); + edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); + edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); + } + state = State::RESETTING; + timer.restartTimer(timID); + } +} + void receiverOperationInitialising() { // If the detection window is not filled, fill it @@ -129,7 +153,8 @@ void receiverOperationDetectingStart() // If there was no gesture recently, update the threshold if (taBuffer[0] - thresholdAdjustmentBuffer[0] >= THRESHOLD_ADJ_BUFFER_LENGTH) { - state = State::UPDATING_THRESHOLD; + state = State::UPDATING_THRESHOLD_AB; + timer.restartTimer(timID); return; } @@ -220,7 +245,7 @@ void receiverOperationDetectingEnd() else { // Gesture took too long -> Light Intensity Change -> Threshold Recalculation - state = State::UPDATING_THRESHOLD; + state = State::UPDATING_THRESHOLD_PB; timer.restartTimer(timID); } } @@ -235,14 +260,7 @@ void receiverOperationResetting() taBuffer[i] = thresholdAdjustmentBuffer[i]; } - if (!endDetected) - { - state = State::UPDATING_THRESHOLD; - } - else - { - state = State::INITIALISING; - } + state = State::INITIALISING; timer.restartTimer(timID); } @@ -262,8 +280,12 @@ void receiverRunOperation() receiverOperationDetectingEnd(); break; - case State::UPDATING_THRESHOLD: - receiverOperationUpdateThreshold(); + case State::UPDATING_THRESHOLD_AB: + receiverOperationUpdateThresholdFromAdjBuffer(); + break; + + case State::UPDATING_THRESHOLD_PB: + receiverOperationUpdateThresholdFromPhoBuffer(); break; case State::UPDATING_THRESHOLD_ACTUAL: From e56c106d84dea28e0795d5d8189a8563664b0674 Mon Sep 17 00:00:00 2001 From: mitko Date: Thu, 16 Jun 2022 16:52:21 +0200 Subject: [PATCH 06/21] Receiver: Refactor - remove usage of pointer buffers. --- src/receiver/receiver.hpp | 100 +++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 55 deletions(-) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 5c86284..91f1f10 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -28,19 +28,18 @@ enum class State State state = State::INITIALISING; -int count = 0; -int threshUpdateCount = 0; -bool detectionWindowFull = false; -bool endDetected = false; +int gestureDataIndex = 0; +int thresholdAdjDataIndex = 0; +int threshUpdateCount = 0; +bool detectionWindowFull = false; +bool endDetected = false; // Buffers for dynamic threshold adjustment uint16_t thresholdAdjustmentBuffer[NUM_PDs][THRESHOLD_ADJ_BUFFER_LENGTH]; -uint16_t *taBuffer[NUM_PDs]; uint16_t thresholdUpdateBuffer[NUM_PDs][THRESHOLD_UPD_BUFFER_LENGTH]; // Buffers for gesture signal capture uint16_t photodiodeData[NUM_PDs][GESTURE_BUFFER_LENGTH]; -uint16_t *photodiodeDataPtr[NUM_PDs]; int gestureSignalLength; GRDiodeReader reader; @@ -82,23 +81,17 @@ void receiverOperationUpdateThresholdFromAdjBuffer() for (size_t i = 0; i < NUM_PDs; i++) { uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_ADJ_BUFFER_LENGTH); - uint16_t deltaL = stable * DETECTION_THRESHOLD_COEFF - edgeDetector[i].getThreshold(); - - if (deltaL > 100) - deltaLBigger = true; - if (deltaL < -100) - deltaLSmaller = true; - - taBuffer[i] = thresholdAdjustmentBuffer[i]; + edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); + edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); } - if (deltaLBigger) - regulator.resistorDown(); - else if (deltaLSmaller) - regulator.resistorUp(); + // if (deltaLBigger) + // regulator.resistorDown(); + // else if (deltaLSmaller) + // regulator.resistorUp(); // Calculate new threshold - state = State::UPDATING_THRESHOLD_ACTUAL; + state = State::RESETTING; } void receiverOperationUpdateThresholdActual() { @@ -126,15 +119,19 @@ void receiverOperationInitialising() // If the detection window is not filled, fill it for (size_t i = 0; i < NUM_PDs; i++) { - reader.read(pds[i], photodiodeDataPtr[i]++); - reader.read(pds[i], taBuffer[i]++); + reader.read(pds[i], &photodiodeData[i][gestureDataIndex]); + reader.read(pds[i], &thresholdAdjustmentBuffer[i][thresholdAdjDataIndex]); } - count++; - if (count == DETECTION_BUFFER_LENGTH) + + thresholdAdjDataIndex++; + + if (gestureDataIndex < DETECTION_BUFFER_LENGTH - 1) { - for (size_t i = 0; i < NUM_PDs; i++) - photodiodeDataPtr[i]--; + gestureDataIndex++; + } + else { state = State::DETECTING_START; + detectionWindowFull = true; } } @@ -146,12 +143,14 @@ void receiverOperationDetectingStart() for (size_t i = 0; i < NUM_PDs; i++) { - reader.read(pds[i], photodiodeDataPtr[i]); - reader.read(pds[i], taBuffer[i]++); + reader.read(pds[i], &photodiodeData[i][gestureDataIndex]); + reader.read(pds[i], &thresholdAdjustmentBuffer[i][thresholdAdjDataIndex]); } + thresholdAdjDataIndex++; + // If there was no gesture recently, update the threshold - if (taBuffer[0] - thresholdAdjustmentBuffer[0] >= THRESHOLD_ADJ_BUFFER_LENGTH) + if (thresholdAdjDataIndex >= THRESHOLD_ADJ_BUFFER_LENGTH - 1) { state = State::UPDATING_THRESHOLD_AB; timer.restartTimer(timID); @@ -161,7 +160,7 @@ void receiverOperationDetectingStart() // Try to detect a start on one of the photodiodes bool startEdgeDetected = false; for (size_t i = 0; i < NUM_PDs; i++) - startEdgeDetected = startEdgeDetected || edgeDetector[i].DetectStart(photodiodeDataPtr[i]); + startEdgeDetected = startEdgeDetected || edgeDetector[i].DetectStart(&photodiodeData[i][gestureDataIndex]); if (detectionWindowFull && startEdgeDetected) { @@ -174,37 +173,30 @@ void receiverOperationDetectingStart() void receiverOperationDetectingEnd() { - // Read enough more data to avoid buffer overflow when checking end - // of gesture if more samples are checked for end than for start - if (count++ < DETECTION_END_WINDOW_LENGTH - DETECTION_BUFFER_LENGTH) - { - for (size_t i = 0; i < NUM_PDs; i++) - { - photodiodeDataPtr[i]++; - reader.read(pds[i], photodiodeDataPtr[i]); - } - return; - } - // Read new data and check for end of gesture - if (count++ < GESTURE_BUFFER_LENGTH) + if (gestureDataIndex < GESTURE_BUFFER_LENGTH - 1) { + gestureDataIndex++; + // Read next sample for (size_t i = 0; i < NUM_PDs; i++) { - photodiodeDataPtr[i]++; - reader.read(pds[i], photodiodeDataPtr[i]); + reader.read(pds[i], &photodiodeData[i][gestureDataIndex]); } + // Read enough more data to avoid buffer overflow when checking end + // of gesture if more samples are checked for end than for start + if (gestureDataIndex < DETECTION_END_WINDOW_LENGTH - 1) return; + // Try to detect end in all photodiodes bool endEdgeDetected = true; for (size_t i = 0; i < NUM_PDs; i++) - endEdgeDetected = endEdgeDetected && edgeDetector[i].DetectEnd(photodiodeDataPtr[i]); + endEdgeDetected = endEdgeDetected && edgeDetector[i].DetectEnd(&photodiodeData[i][gestureDataIndex]); if (endEdgeDetected) { // Determine the gesture length - gestureSignalLength = photodiodeDataPtr[0] - photodiodeData[0] + 1; + gestureSignalLength = gestureDataIndex + 1; // Reject gestures that took too short time if (gestureSignalLength < GESTURE_MIN_TIME_MS / READ_PERIOD + 1) @@ -229,6 +221,7 @@ void receiverOperationDetectingEnd() thresholds[i] = edgeDetector[i].getCutOffThreshold(); } + Serial.println("Running pipeline ..."); pipeline.RunPipeline(photodiodeData, gestureSignalLength, thresholds); float(*output)[100] = pipeline.getPipelineOutput(); @@ -254,11 +247,8 @@ void receiverOperationResetting() { // Reset the buffer pointers for PD gesture data collection detectionWindowFull = false; - for (size_t i = 0; i < NUM_PDs; i++) - { - photodiodeDataPtr[i] = photodiodeData[i]; - taBuffer[i] = thresholdAdjustmentBuffer[i]; - } + gestureDataIndex = 0; + thresholdAdjDataIndex = 0; state = State::INITIALISING; timer.restartTimer(timID); @@ -306,9 +296,7 @@ void receiverSetup() for (size_t i = 0; i < NUM_PDs; i++) { pinMode(pds[i], INPUT); - taBuffer[i] = thresholdAdjustmentBuffer[i]; - photodiodeDataPtr[i] = photodiodeData[i]; - edgeDetector[i] = GREdgeDetector(DETECTION_WINDOW_LENGTH, DETECTION_END_WINDOW_LENGTH, 750); + edgeDetector[i] = GREdgeDetector(DETECTION_WINDOW_LENGTH, DETECTION_END_WINDOW_LENGTH, 500); } Serial.begin(9600); @@ -317,5 +305,7 @@ void receiverSetup() void receiverLoop() { - timer.run(); + // Serial.println("Running operation: "); + // Serial.println(static_cast(state)); + receiverRunOperation(); } \ No newline at end of file From 112a84e2543ca5ba680433af339c96efd99cf5e2 Mon Sep 17 00:00:00 2001 From: mitko Date: Thu, 16 Jun 2022 17:27:47 +0200 Subject: [PATCH 07/21] Receiver: Comments and renaming. --- src/receiver/receiver.hpp | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 91f1f10..1663a49 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -15,6 +15,10 @@ #include "../diode_calibration/diode_calibration.h" +/** + * @brief An enum for the different receiver stages of computation. Used for creating FSM architecture. + * + */ enum class State { INITIALISING, @@ -26,31 +30,35 @@ enum class State RESETTING }; +// The current receiver state in the FSM State state = State::INITIALISING; -int gestureDataIndex = 0; -int thresholdAdjDataIndex = 0; -int threshUpdateCount = 0; +// flags that indicate whether enough PD data is read for start detection to begin +// and whether an end is successfully detected from an actual gesture bool detectionWindowFull = false; bool endDetected = false; // Buffers for dynamic threshold adjustment uint16_t thresholdAdjustmentBuffer[NUM_PDs][THRESHOLD_ADJ_BUFFER_LENGTH]; -uint16_t thresholdUpdateBuffer[NUM_PDs][THRESHOLD_UPD_BUFFER_LENGTH]; +int thresholdAdjDataIndex = 0; // Buffers for gesture signal capture uint16_t photodiodeData[NUM_PDs][GESTURE_BUFFER_LENGTH]; + +// Current index in the buffer for new photodiode data to be written to +int gestureDataIndex = 0; + +// Detected gesture signal length int gestureSignalLength; GRDiodeReader reader; GREdgeDetector edgeDetector[NUM_PDs]; GRPreprocessingPipeline pipeline; +LightIntensityRegulator regulator; SimpleTimer timer; int timID; -LightIntensityRegulator regulator; - void receiverOperationUpdateThresholdFromPhoBuffer() { bool deltaLBigger = false, deltaLSmaller = false; @@ -95,17 +103,22 @@ void receiverOperationUpdateThresholdFromAdjBuffer() } void receiverOperationUpdateThresholdActual() { - if (threshUpdateCount < THRESHOLD_UPD_BUFFER_LENGTH) { + thresholdAdjDataIndex = 0; + + if (thresholdAdjDataIndex < THRESHOLD_UPD_BUFFER_LENGTH - 1) + { for (size_t i = 0; i < NUM_PDs; i++) { - reader.read(pds[i], thresholdUpdateBuffer[i] + threshUpdateCount); + reader.read(pds[i], &thresholdAdjustmentBuffer[i][thresholdAdjDataIndex]); } - threshUpdateCount++; - } else { - threshUpdateCount = 0; + + thresholdAdjDataIndex++; + } + else + { for (size_t i = 0; i < NUM_PDs; i++) { - uint16_t stable = QuickMedian::GetMedian(thresholdUpdateBuffer[i], THRESHOLD_UPD_BUFFER_LENGTH); + uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_UPD_BUFFER_LENGTH); edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); } From dcd27babc2b8335fde7268e0093b1280a2c26633 Mon Sep 17 00:00:00 2001 From: mitko Date: Thu, 16 Jun 2022 18:09:08 +0200 Subject: [PATCH 08/21] Receiver: Document FSM. --- src/receiver/receiver.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 1663a49..eabbd76 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -267,6 +267,17 @@ void receiverOperationResetting() timer.restartTimer(timID); } +/** + * @brief FSM state operation selection. + * + * INITIALISING - collect enough data before beginning start detection. + * DETECTING_START - start detection + * DETECTING_END - end detection and pipeline running + * UPDATING_THRESHOLD_AB - update the edge detection threshold after a gesture wasnt performed for some time + * UPDATING_THRESHOLD_PB - update the edge detection threshold in case a gesture was too long + * UPDATING_THRESHOLD_ACTUAL - only this state updates the edge detection threshold by collecting data and find its medium + * RESETTING - reset the counters and go back to INITIALISING + */ void receiverRunOperation() { switch (state) From 094ae421bfc0d47e5babc57012cb59c47720f8a3 Mon Sep 17 00:00:00 2001 From: mitko Date: Thu, 16 Jun 2022 18:30:07 +0200 Subject: [PATCH 09/21] Add timer restart. --- src/receiver/receiver.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index eabbd76..5b44a13 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -80,6 +80,7 @@ void receiverOperationUpdateThresholdFromPhoBuffer() { // Calculate new threshold state = State::UPDATING_THRESHOLD_ACTUAL; + timer.restartTimer(timID); } void receiverOperationUpdateThresholdFromAdjBuffer() @@ -100,6 +101,7 @@ void receiverOperationUpdateThresholdFromAdjBuffer() // Calculate new threshold state = State::RESETTING; + timer.restartTimer(timID); } void receiverOperationUpdateThresholdActual() { From 6d5c5a5a345c33d3be4609699491333b97ef7b7a Mon Sep 17 00:00:00 2001 From: mitko Date: Thu, 16 Jun 2022 23:07:30 +0200 Subject: [PATCH 10/21] BugFix: Reset counter. --- src/receiver/receiver.hpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 5b44a13..93fcfcc 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -102,11 +102,10 @@ void receiverOperationUpdateThresholdFromAdjBuffer() // Calculate new threshold state = State::RESETTING; timer.restartTimer(timID); + thresholdAdjDataIndex = 0; } void receiverOperationUpdateThresholdActual() { - thresholdAdjDataIndex = 0; - if (thresholdAdjDataIndex < THRESHOLD_UPD_BUFFER_LENGTH - 1) { for (size_t i = 0; i < NUM_PDs; i++) @@ -174,15 +173,13 @@ void receiverOperationDetectingStart() // Try to detect a start on one of the photodiodes bool startEdgeDetected = false; - for (size_t i = 0; i < NUM_PDs; i++) - startEdgeDetected = startEdgeDetected || edgeDetector[i].DetectStart(&photodiodeData[i][gestureDataIndex]); - - if (detectionWindowFull && startEdgeDetected) - { - state = State::DETECTING_END; + for (size_t i = 0; i < NUM_PDs; i++){ + if(edgeDetector[i].DetectStart(&photodiodeData[i][gestureDataIndex])){ + state = State::DETECTING_END; #ifdef DEBUG_RECEIVER - Serial.println("Gesture started"); + Serial.println("Gesture started"); #endif + } } } From 4703d5c1c44c50f56db2da024a5f7b58d972b536 Mon Sep 17 00:00:00 2001 From: mitko Date: Fri, 17 Jun 2022 13:15:51 +0200 Subject: [PATCH 11/21] BugFix: Actually run timer. --- src/main.cpp | 25 ++++++++++++++++++++----- src/receiver/receiver.hpp | 23 ++++++++++------------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 627ddb1..0f241e0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,22 +26,37 @@ void plotter() { void setup() { Serial.begin(9600); - //while(!Serial); + while(!Serial); // Start visualization thread. Comment out if no visualization/data_collection is required - plotter_thread.start(plotter); + // plotter_thread.start(plotter); // Setup the lightintensity regulator. regulator = new LightIntensityRegulator(); - //tensorflowSetup(); - //receiverSetup(); + // tensorflowSetup(); + receiverSetup(regulator); + + // pinMode(A0, ANALOG); + // pinMode(A1, INPUT); + // pinMode(A2, INPUT); } void loop() { - //receiverLoop(); + // int r0 = analogRead(A0); + // int r1 = analogRead(A1); + // int r2 = analogRead(A2); + + // Serial.print(r0); + // Serial.print(", "); + // Serial.print(r1); + // Serial.print(", "); + // Serial.println(r2); + // delay(10); + + receiverLoop(); } diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 93fcfcc..6ba8a5a 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -54,7 +54,7 @@ int gestureSignalLength; GRDiodeReader reader; GREdgeDetector edgeDetector[NUM_PDs]; GRPreprocessingPipeline pipeline; -LightIntensityRegulator regulator; +LightIntensityRegulator * recRegulator; SimpleTimer timer; int timID; @@ -74,9 +74,9 @@ void receiverOperationUpdateThresholdFromPhoBuffer() { } if (deltaLBigger) - regulator.resistorDown(); + recRegulator->resistorDown(); else if (deltaLSmaller) - regulator.resistorUp(); + recRegulator->resistorUp(); // Calculate new threshold state = State::UPDATING_THRESHOLD_ACTUAL; @@ -176,9 +176,7 @@ void receiverOperationDetectingStart() for (size_t i = 0; i < NUM_PDs; i++){ if(edgeDetector[i].DetectStart(&photodiodeData[i][gestureDataIndex])){ state = State::DETECTING_END; -#ifdef DEBUG_RECEIVER - Serial.println("Gesture started"); -#endif + timer.restartTimer(timID); } } } @@ -238,10 +236,10 @@ void receiverOperationDetectingEnd() float(*output)[100] = pipeline.getPipelineOutput(); - Gesture g = inferGesture2d(output); + // Gesture g = inferGesture2d(output); - Serial.print("Gesture: "); - Serial.println(g); + // Serial.print("Gesture: "); + // Serial.println(g); state = State::RESETTING; timer.restartTimer(timID); @@ -314,8 +312,9 @@ void receiverRunOperation() } } -void receiverSetup() +void receiverSetup(LightIntensityRegulator * regulator) { + recRegulator = regulator; for (size_t i = 0; i < NUM_PDs; i++) { pinMode(pds[i], INPUT); @@ -328,7 +327,5 @@ void receiverSetup() void receiverLoop() { - // Serial.println("Running operation: "); - // Serial.println(static_cast(state)); - receiverRunOperation(); + timer.run(); } \ No newline at end of file From cacd7c2d02eb4ac7379bf25c72b2df4c30b09ecc Mon Sep 17 00:00:00 2001 From: mitko Date: Fri, 17 Jun 2022 13:21:55 +0200 Subject: [PATCH 12/21] Calibration: Include only once. --- src/diode_calibration/diode_calibration.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/diode_calibration/diode_calibration.h b/src/diode_calibration/diode_calibration.h index 8f3b8d0..b2f05b2 100644 --- a/src/diode_calibration/diode_calibration.h +++ b/src/diode_calibration/diode_calibration.h @@ -1,3 +1,6 @@ +#ifndef CALIBRATION +#define CALIBRATION + #include "Arduino.h" #include #include @@ -186,4 +189,6 @@ class LightIntensityRegulator { } return read_sum / window; } -}; \ No newline at end of file +}; + +#endif \ No newline at end of file From 3366435067951e4930777f6065ad36e821e83b6d Mon Sep 17 00:00:00 2001 From: mitko Date: Fri, 17 Jun 2022 13:34:28 +0200 Subject: [PATCH 13/21] Receiver: Use hardware adjustment. --- src/receiver/receiver.hpp | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 6ba8a5a..440538d 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -83,7 +83,7 @@ void receiverOperationUpdateThresholdFromPhoBuffer() { timer.restartTimer(timID); } -void receiverOperationUpdateThresholdFromAdjBuffer() +void receiverOperationUpdateThresholdFromAdjBuffer_NoHardware() { bool deltaLBigger = false, deltaLSmaller = false; @@ -94,17 +94,38 @@ void receiverOperationUpdateThresholdFromAdjBuffer() edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); } - // if (deltaLBigger) - // regulator.resistorDown(); - // else if (deltaLSmaller) - // regulator.resistorUp(); - // Calculate new threshold state = State::RESETTING; timer.restartTimer(timID); thresholdAdjDataIndex = 0; } +void receiverOperationUpdateThresholdFromAdjBuffer() +{ + bool deltaLBigger = false, deltaLSmaller = false; + + for (size_t i = 0; i < NUM_PDs; i++) + { + uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_ADJ_BUFFER_LENGTH); + uint16_t deltaL = stable * DETECTION_THRESHOLD_COEFF - edgeDetector[i].getThreshold(); + + if (deltaL > 100) + deltaLBigger = true; + if (deltaL < -100) + deltaLSmaller = true; + } + + if (deltaLBigger) + recRegulator->resistorDown(); + else if (deltaLSmaller) + recRegulator->resistorUp(); + + // Calculate new threshold + state = State::UPDATING_THRESHOLD_ACTUAL; + timer.restartTimer(timID); + thresholdAdjDataIndex = 0; +} + void receiverOperationUpdateThresholdActual() { if (thresholdAdjDataIndex < THRESHOLD_UPD_BUFFER_LENGTH - 1) { From 8682f606b0b9d59a16899dd964afc2a8f59f1132 Mon Sep 17 00:00:00 2001 From: mitko Date: Fri, 17 Jun 2022 15:09:12 +0200 Subject: [PATCH 14/21] Receiver: Add comments. --- src/receiver/receiver.hpp | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 440538d..cb32753 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -33,19 +33,24 @@ enum class State // The current receiver state in the FSM State state = State::INITIALISING; -// flags that indicate whether enough PD data is read for start detection to begin -// and whether an end is successfully detected from an actual gesture +// flag - indicates whether enough PD data is read for start detection to begin bool detectionWindowFull = false; + +// flag - indicates whether an end is successfully detected from a long enough gesture bool endDetected = false; // Buffers for dynamic threshold adjustment uint16_t thresholdAdjustmentBuffer[NUM_PDs][THRESHOLD_ADJ_BUFFER_LENGTH]; + +// Current index in the threshold adjustment buffer +// for new photodiode data to be written to int thresholdAdjDataIndex = 0; // Buffers for gesture signal capture uint16_t photodiodeData[NUM_PDs][GESTURE_BUFFER_LENGTH]; -// Current index in the buffer for new photodiode data to be written to +// Current index in the gesture signal buffer +// for new photodiode data to be written to int gestureDataIndex = 0; // Detected gesture signal length @@ -56,12 +61,16 @@ GREdgeDetector edgeDetector[NUM_PDs]; GRPreprocessingPipeline pipeline; LightIntensityRegulator * recRegulator; +// Software timer based on millis() used for sampling period accuracy SimpleTimer timer; int timID; void receiverOperationUpdateThresholdFromPhoBuffer() { bool deltaLBigger = false, deltaLSmaller = false; + // For each photodiode - find its current stable signal and + // compare it with the previous one. + // Use the gesture data from a too long gesture for (size_t i = 0; i < NUM_PDs; i++) { uint16_t stable = QuickMedian::GetMedian(photodiodeData[i], GESTURE_BUFFER_LENGTH); @@ -73,28 +82,31 @@ void receiverOperationUpdateThresholdFromPhoBuffer() { deltaLSmaller = true; } + // Update the photodiode sensitivity using the calibration module if needed. if (deltaLBigger) recRegulator->resistorDown(); else if (deltaLSmaller) recRegulator->resistorUp(); - // Calculate new threshold + // Continue to new threshold computation state = State::UPDATING_THRESHOLD_ACTUAL; timer.restartTimer(timID); } +// This is a utility function ONLY for DEBUGGING without the usage +// of hardware adjustment. void receiverOperationUpdateThresholdFromAdjBuffer_NoHardware() { bool deltaLBigger = false, deltaLSmaller = false; for (size_t i = 0; i < NUM_PDs; i++) { + // Calculate new threshold uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_ADJ_BUFFER_LENGTH); edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); } - // Calculate new threshold state = State::RESETTING; timer.restartTimer(timID); thresholdAdjDataIndex = 0; @@ -104,6 +116,9 @@ void receiverOperationUpdateThresholdFromAdjBuffer() { bool deltaLBigger = false, deltaLSmaller = false; + // For each photodiode - find its current stable signal and + // compare it with the previous one. + // Use the photodiode data collected without a gesture being detected for (size_t i = 0; i < NUM_PDs; i++) { uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_ADJ_BUFFER_LENGTH); @@ -115,18 +130,20 @@ void receiverOperationUpdateThresholdFromAdjBuffer() deltaLSmaller = true; } + // Update the photodiode sensitivity using the calibration module if needed. if (deltaLBigger) recRegulator->resistorDown(); else if (deltaLSmaller) recRegulator->resistorUp(); - // Calculate new threshold + // Continue to new threshold computation state = State::UPDATING_THRESHOLD_ACTUAL; timer.restartTimer(timID); thresholdAdjDataIndex = 0; } void receiverOperationUpdateThresholdActual() { + // Collect enough data for threshold computation if (thresholdAdjDataIndex < THRESHOLD_UPD_BUFFER_LENGTH - 1) { for (size_t i = 0; i < NUM_PDs; i++) @@ -138,6 +155,7 @@ void receiverOperationUpdateThresholdActual() { } else { + // Calculate the new thresholds for the photodiodes using the median of the collected data for (size_t i = 0; i < NUM_PDs; i++) { uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_UPD_BUFFER_LENGTH); @@ -286,7 +304,7 @@ void receiverOperationResetting() } /** - * @brief FSM state operation selection. + * FSM state operation selection. * * INITIALISING - collect enough data before beginning start detection. * DETECTING_START - start detection From 15675866a1848b2a9b07e4785ac8012847c1ec02 Mon Sep 17 00:00:00 2001 From: mitko Date: Fri, 17 Jun 2022 15:42:24 +0200 Subject: [PATCH 15/21] Receiver: Refactor GDDiodeReader and others. --- src/receiver/GRDiodeReader.h | 10 ++++++++++ src/receiver/receiver.hpp | 31 ++++++++++--------------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/receiver/GRDiodeReader.h b/src/receiver/GRDiodeReader.h index 5d7516a..26fde49 100644 --- a/src/receiver/GRDiodeReader.h +++ b/src/receiver/GRDiodeReader.h @@ -1,5 +1,7 @@ #include +#include "receiver-parameters.h" + /** * @brief A class abstracting the reading of sensors and storing their input. * @@ -12,4 +14,12 @@ class GRDiodeReader { void read(uint8_t d, uint16_t * dest) { *dest = analogRead(d); } + + template + void readAll(uint16_t dest[NUM_PDs][size],int index) { + for (size_t i = 0; i < NUM_PDs; i++) + { + this->read(pds[i], &dest[i][index]); + } + } }; \ No newline at end of file diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index cb32753..e91e720 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -1,3 +1,5 @@ +#define USE_ARDUINO + #include #include #include @@ -146,11 +148,7 @@ void receiverOperationUpdateThresholdActual() { // Collect enough data for threshold computation if (thresholdAdjDataIndex < THRESHOLD_UPD_BUFFER_LENGTH - 1) { - for (size_t i = 0; i < NUM_PDs; i++) - { - reader.read(pds[i], &thresholdAdjustmentBuffer[i][thresholdAdjDataIndex]); - } - + reader.readAll(thresholdAdjustmentBuffer, thresholdAdjDataIndex); thresholdAdjDataIndex++; } else @@ -170,11 +168,8 @@ void receiverOperationUpdateThresholdActual() { void receiverOperationInitialising() { // If the detection window is not filled, fill it - for (size_t i = 0; i < NUM_PDs; i++) - { - reader.read(pds[i], &photodiodeData[i][gestureDataIndex]); - reader.read(pds[i], &thresholdAdjustmentBuffer[i][thresholdAdjDataIndex]); - } + reader.readAll(photodiodeData, gestureDataIndex); + reader.readAll(thresholdAdjustmentBuffer, thresholdAdjDataIndex); thresholdAdjDataIndex++; @@ -194,11 +189,8 @@ void receiverOperationDetectingStart() // and put the new sample in the last place FOR(di, i, NUM_PDs, DETECTION_BUFFER_LENGTH - 1, photodiodeData[di][i] = photodiodeData[di][i + 1]) - for (size_t i = 0; i < NUM_PDs; i++) - { - reader.read(pds[i], &photodiodeData[i][gestureDataIndex]); - reader.read(pds[i], &thresholdAdjustmentBuffer[i][thresholdAdjDataIndex]); - } + reader.readAll(photodiodeData, gestureDataIndex); + reader.readAll(thresholdAdjustmentBuffer, gestureDataIndex); thresholdAdjDataIndex++; @@ -211,11 +203,11 @@ void receiverOperationDetectingStart() } // Try to detect a start on one of the photodiodes - bool startEdgeDetected = false; for (size_t i = 0; i < NUM_PDs; i++){ if(edgeDetector[i].DetectStart(&photodiodeData[i][gestureDataIndex])){ state = State::DETECTING_END; timer.restartTimer(timID); + break; } } } @@ -228,10 +220,7 @@ void receiverOperationDetectingEnd() gestureDataIndex++; // Read next sample - for (size_t i = 0; i < NUM_PDs; i++) - { - reader.read(pds[i], &photodiodeData[i][gestureDataIndex]); - } + reader.readAll(photodiodeData, gestureDataIndex); // Read enough more data to avoid buffer overflow when checking end // of gesture if more samples are checked for end than for start @@ -251,7 +240,7 @@ void receiverOperationDetectingEnd() if (gestureSignalLength < GESTURE_MIN_TIME_MS / READ_PERIOD + 1) { #ifdef DEBUG_RECEIVER - Serial.println("Gesture took too little time! Rejecting and starting over ..."); + Serial.println("Gesture took too little time! Rejecting and starting over ..."); #endif state = State::RESETTING; timer.restartTimer(timID); From 59f0b29499b3254434b26d4b7cfd08cdb75ea096 Mon Sep 17 00:00:00 2001 From: mitko Date: Fri, 17 Jun 2022 15:51:24 +0200 Subject: [PATCH 16/21] Receiver: Refactor - extract hardware adjustment in a function. --- src/receiver/receiver.hpp | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index e91e720..e857bd5 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -67,7 +67,9 @@ LightIntensityRegulator * recRegulator; SimpleTimer timer; int timID; -void receiverOperationUpdateThresholdFromPhoBuffer() { +template +void checkLightIntensityAndAdjustHardware(uint16_t data[NUM_PDs][size]) +{ bool deltaLBigger = false, deltaLSmaller = false; // For each photodiode - find its current stable signal and @@ -75,7 +77,7 @@ void receiverOperationUpdateThresholdFromPhoBuffer() { // Use the gesture data from a too long gesture for (size_t i = 0; i < NUM_PDs; i++) { - uint16_t stable = QuickMedian::GetMedian(photodiodeData[i], GESTURE_BUFFER_LENGTH); + uint16_t stable = QuickMedian::GetMedian(data[i], size); uint16_t deltaL = stable * DETECTION_THRESHOLD_COEFF - edgeDetector[i].getThreshold(); if (deltaL > 100) @@ -89,12 +91,18 @@ void receiverOperationUpdateThresholdFromPhoBuffer() { recRegulator->resistorDown(); else if (deltaLSmaller) recRegulator->resistorUp(); +} + +void receiverOperationUpdateThresholdFromPhoBuffer() +{ + checkLightIntensityAndAdjustHardware(photodiodeData); // Continue to new threshold computation state = State::UPDATING_THRESHOLD_ACTUAL; timer.restartTimer(timID); } +#ifdef DEBUG_RECEIVER // This is a utility function ONLY for DEBUGGING without the usage // of hardware adjustment. void receiverOperationUpdateThresholdFromAdjBuffer_NoHardware() @@ -113,30 +121,11 @@ void receiverOperationUpdateThresholdFromAdjBuffer_NoHardware() timer.restartTimer(timID); thresholdAdjDataIndex = 0; } +#endif void receiverOperationUpdateThresholdFromAdjBuffer() { - bool deltaLBigger = false, deltaLSmaller = false; - - // For each photodiode - find its current stable signal and - // compare it with the previous one. - // Use the photodiode data collected without a gesture being detected - for (size_t i = 0; i < NUM_PDs; i++) - { - uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_ADJ_BUFFER_LENGTH); - uint16_t deltaL = stable * DETECTION_THRESHOLD_COEFF - edgeDetector[i].getThreshold(); - - if (deltaL > 100) - deltaLBigger = true; - if (deltaL < -100) - deltaLSmaller = true; - } - - // Update the photodiode sensitivity using the calibration module if needed. - if (deltaLBigger) - recRegulator->resistorDown(); - else if (deltaLSmaller) - recRegulator->resistorUp(); + checkLightIntensityAndAdjustHardware(photodiodeData); // Continue to new threshold computation state = State::UPDATING_THRESHOLD_ACTUAL; From 128573a442754943adc65e5ac92a3661005cd1f8 Mon Sep 17 00:00:00 2001 From: mitko Date: Fri, 17 Jun 2022 15:57:33 +0200 Subject: [PATCH 17/21] Receiver: Refactor - use externally passed functions for hardware adjustment. --- src/main.cpp | 2 +- src/receiver/receiver.hpp | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0f241e0..7614f0b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,7 +35,7 @@ void setup() { regulator = new LightIntensityRegulator(); // tensorflowSetup(); - receiverSetup(regulator); + receiverSetup([]{regulator->resistorDown();}, []{regulator->resistorUp();}); // pinMode(A0, ANALOG); // pinMode(A1, INPUT); diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index e857bd5..9985e23 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -15,8 +15,6 @@ #include "../ml-arduino/prediction_enums.hpp" #include "../ml-arduino/main_arduino.hpp" -#include "../diode_calibration/diode_calibration.h" - /** * @brief An enum for the different receiver stages of computation. Used for creating FSM architecture. * @@ -61,12 +59,14 @@ int gestureSignalLength; GRDiodeReader reader; GREdgeDetector edgeDetector[NUM_PDs]; GRPreprocessingPipeline pipeline; -LightIntensityRegulator * recRegulator; // Software timer based on millis() used for sampling period accuracy SimpleTimer timer; int timID; +void (*updateForMoreLight)(); +void (*updateForLessLight)(); + template void checkLightIntensityAndAdjustHardware(uint16_t data[NUM_PDs][size]) { @@ -88,9 +88,9 @@ void checkLightIntensityAndAdjustHardware(uint16_t data[NUM_PDs][size]) // Update the photodiode sensitivity using the calibration module if needed. if (deltaLBigger) - recRegulator->resistorDown(); + updateForMoreLight(); else if (deltaLSmaller) - recRegulator->resistorUp(); + updateForLessLight(); } void receiverOperationUpdateThresholdFromPhoBuffer() @@ -329,9 +329,11 @@ void receiverRunOperation() } } -void receiverSetup(LightIntensityRegulator * regulator) +void receiverSetup(void (*extUpdateForMoreLight)(), void (*extUpdateForLessLight)()) { - recRegulator = regulator; + updateForLessLight = extUpdateForLessLight; + updateForMoreLight = extUpdateForMoreLight; + for (size_t i = 0; i < NUM_PDs; i++) { pinMode(pds[i], INPUT); From d0331348cee70d6b0eb340cb5501c1899fd17e8c Mon Sep 17 00:00:00 2001 From: mitko Date: Sun, 19 Jun 2022 22:27:10 +0200 Subject: [PATCH 18/21] Receiver: Add trimming after FFT to real-time receiver. --- src/receiver/GRPreprocessingPipeline.h | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/receiver/GRPreprocessingPipeline.h b/src/receiver/GRPreprocessingPipeline.h index ad4fc93..8f14c4c 100644 --- a/src/receiver/GRPreprocessingPipeline.h +++ b/src/receiver/GRPreprocessingPipeline.h @@ -47,10 +47,10 @@ class GRPreprocessingPipeline { bool trimmed = false; int trimCount = 0; int i = gestureSignalLength; - while(i-- >= 0 && trimCount++ < DETECTION_END_WINDOW_LENGTH * DETECTION_END_WINDOW_TRIM) { + while(i-- >= 0) { bool zero = true; for (size_t di = 0; di < NUM_PDs; di++) - zero = zero && (rawData[di][i] <= 1); + zero = zero && (rawData[di][i] == 0); if (zero) { trimmed = true; @@ -72,7 +72,7 @@ class GRPreprocessingPipeline { for (size_t i = 0; i < NUM_PDs; i++) { fftFilter[i].ZeroImag(); - fftFilter[i].Filter(rawData[i], gestureSignalLength, 5, 1000 / READ_PERIOD); + fftFilter[i].Filter(rawData[i], gestureSignalLength, 10, 1000 / READ_PERIOD); fftFilter[i].MoveDataToBufferF(photodiodeDataFFTFiltered[i]); } @@ -81,6 +81,21 @@ class GRPreprocessingPipeline { FOR(di, i, NUM_PDs, gestureSignalLength, photodiodeDataFFTFiltered[di][i] = max(0, photodiodeDataFFTFiltered[di][i] - thresholds[di] * CUTT_OFF_THRESHOLD_COEFF_POST_FFT); ); + + trimmed = false; + trimCount = 0; + i = gestureSignalLength; + while(i-- >= 0) { + bool zero = true; + for (size_t di = 0; di < NUM_PDs; di++) + zero = zero && (photodiodeDataFFTFiltered[di][i] == 0); + + if (zero) { + trimmed = true; + gestureSignalLength--; + } + } + if(trimmed) gestureSignalLength++; #ifdef PLOT_RECEIVER sendSignal(photodiodeDataFFTFiltered, FFT_SIGNAL_LENGTH); From a3887f8bb0a3617c1c0d15ed7a99d3549a2ca776 Mon Sep 17 00:00:00 2001 From: mitko Date: Tue, 21 Jun 2022 10:46:38 +0200 Subject: [PATCH 19/21] BugFix: Change fn invoke parameter. --- src/receiver/receiver.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 9985e23..8df0bcc 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -125,7 +125,7 @@ void receiverOperationUpdateThresholdFromAdjBuffer_NoHardware() void receiverOperationUpdateThresholdFromAdjBuffer() { - checkLightIntensityAndAdjustHardware(photodiodeData); + checkLightIntensityAndAdjustHardware(thresholdAdjustmentBuffer); // Continue to new threshold computation state = State::UPDATING_THRESHOLD_ACTUAL; From 3f3a397db3b02523be0e969046b157272970be14 Mon Sep 17 00:00:00 2001 From: mitko Date: Tue, 21 Jun 2022 14:04:30 +0200 Subject: [PATCH 20/21] Receiver: Add feature selection macro that disables hardware adjustment. --- src/receiver/receiver-parameters.h | 1 + src/receiver/receiver.hpp | 65 ++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/receiver/receiver-parameters.h b/src/receiver/receiver-parameters.h index 6ee84ba..22e1917 100644 --- a/src/receiver/receiver-parameters.h +++ b/src/receiver/receiver-parameters.h @@ -54,6 +54,7 @@ }; // #define DEBUG_RECEIVER +// #define NO_HARDWARE_ADJUSTMENT // #define PLOT_RECEIVER #endif diff --git a/src/receiver/receiver.hpp b/src/receiver/receiver.hpp index 8df0bcc..498affb 100644 --- a/src/receiver/receiver.hpp +++ b/src/receiver/receiver.hpp @@ -67,6 +67,48 @@ int timID; void (*updateForMoreLight)(); void (*updateForLessLight)(); +#ifdef NO_HARDWARE_ADJUSTMENT + +// This is a utility function ONLY for DEBUGGING without the usage +// of hardware adjustment. +void receiverOperationUpdateThresholdFromPhoBuffer() +{ + bool deltaLBigger = false, deltaLSmaller = false; + + for (size_t i = 0; i < NUM_PDs; i++) + { + // Calculate new threshold + uint16_t stable = QuickMedian::GetMedian(photodiodeData[i], GESTURE_BUFFER_LENGTH); + edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); + edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); + } + + state = State::RESETTING; + timer.restartTimer(timID); + thresholdAdjDataIndex = 0; +} + +// This is a utility function ONLY for DEBUGGING without the usage +// of hardware adjustment. +void receiverOperationUpdateThresholdFromAdjBuffer() +{ + bool deltaLBigger = false, deltaLSmaller = false; + + for (size_t i = 0; i < NUM_PDs; i++) + { + // Calculate new threshold + uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_ADJ_BUFFER_LENGTH); + edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); + edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); + } + + state = State::RESETTING; + timer.restartTimer(timID); + thresholdAdjDataIndex = 0; +} + +#else + template void checkLightIntensityAndAdjustHardware(uint16_t data[NUM_PDs][size]) { @@ -102,27 +144,6 @@ void receiverOperationUpdateThresholdFromPhoBuffer() timer.restartTimer(timID); } -#ifdef DEBUG_RECEIVER -// This is a utility function ONLY for DEBUGGING without the usage -// of hardware adjustment. -void receiverOperationUpdateThresholdFromAdjBuffer_NoHardware() -{ - bool deltaLBigger = false, deltaLSmaller = false; - - for (size_t i = 0; i < NUM_PDs; i++) - { - // Calculate new threshold - uint16_t stable = QuickMedian::GetMedian(thresholdAdjustmentBuffer[i], THRESHOLD_ADJ_BUFFER_LENGTH); - edgeDetector[i].setThreshold(stable * DETECTION_THRESHOLD_COEFF); - edgeDetector[i].setCutOffThreshold(stable * CUTT_OFF_THRESHOLD_COEFF); - } - - state = State::RESETTING; - timer.restartTimer(timID); - thresholdAdjDataIndex = 0; -} -#endif - void receiverOperationUpdateThresholdFromAdjBuffer() { checkLightIntensityAndAdjustHardware(thresholdAdjustmentBuffer); @@ -133,6 +154,8 @@ void receiverOperationUpdateThresholdFromAdjBuffer() thresholdAdjDataIndex = 0; } +#endif + void receiverOperationUpdateThresholdActual() { // Collect enough data for threshold computation if (thresholdAdjDataIndex < THRESHOLD_UPD_BUFFER_LENGTH - 1) From 9b5476097075b4f188da715f1db51c6ba9e80096 Mon Sep 17 00:00:00 2001 From: mitko Date: Tue, 21 Jun 2022 14:05:00 +0200 Subject: [PATCH 21/21] Receiver: Add README. --- src/receiver/README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/receiver/README.md diff --git a/src/receiver/README.md b/src/receiver/README.md new file mode 100644 index 0000000..7eb9e2e --- /dev/null +++ b/src/receiver/README.md @@ -0,0 +1,32 @@ +# Real-time Photodiode (PD) - based Gesture Receiver + +## Directory Structure +- [receiver.hpp](receiver.hpp) : receiver main file, containing its FSM architecture + +- [receiver-parameters.h](receiver-parameters.h) : various macros and photodiode pins setups for use by the rest of the files + +- [receiver-util.h](receiver-util.h) : auxiliary utility macros and functions + +- [GRDiodeReader.h](GRDiodeReader.h) : abstraction over PD reading. Used in [receiver.hpp](receiver.hpp). + +- [GREdgeDetector.h](GREdgeDetector.h) : abstraction over checking for gesture start and end using an adjustable threshold. Used in [receiver.hpp](receiver.hpp). + +- [GRPreprocessingPipeline.h](GRPreprocessingPipeline.h) + [pipeline-stages/](pipeline-stages/) : pipeline for noise reduction and normalisation of gesture data. Used in [receiver.hpp](receiver.hpp). + +- [plotting/](plotting/) : auxiliary files for plotting the output of the preprocessing pipeline stages. + + +## Plotting the receiver pipeline stages' outputs: + +* Go to `receiver-parameters.h` and uncomment the `PLOT_RECEIVER` macro. +* After starting the system on the Arduino connected via a serial port, run the Python script [plotter.py](plotting/plotter.py). + +## Debugging the receiver main FSM: + +* Go to `receiver-parameters.h` and uncomment the `DEBUG_RECEIVER` macro. +* Start the system on the Arduino connected via a serial port and monitor the port input. + +## Turning off hardware adjustment and only using software threshold adjustment + +* Go to `receiver-parameters.h` and uncomment the `NO_HARDWARE_ADJUSTMENT` macro. +