From 26bcddb6230070744cc39c7eab5ac1ac505d4513 Mon Sep 17 00:00:00 2001 From: PloopyCo Date: Mon, 25 Nov 2019 12:33:00 -0500 Subject: [PATCH] scroll wheel is now done with a stochastic algorithm to make up for the inherent noise in the phototransistor --- firmware/production/Scroller.cpp | 188 ++++++++++++++++++++++++----- firmware/production/Scroller.h | 29 ++++- firmware/production/production.ino | 7 +- 3 files changed, 186 insertions(+), 38 deletions(-) diff --git a/firmware/production/Scroller.cpp b/firmware/production/Scroller.cpp index 22500d0..2859f7d 100644 --- a/firmware/production/Scroller.cpp +++ b/firmware/production/Scroller.cpp @@ -17,6 +17,9 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#endif #include "Scroller.h" Scroller::Scroller(void) { @@ -25,15 +28,29 @@ Scroller::Scroller(void) { hilof = false; lowA = 1023; highA = 0; + cLowA = false; + cHighA = false; + lowIndexA = 0; + highIndexA = 0; + lowOverflowA = false; + highOverflowA = false; lowB = 1023; highB = 0; + cLowB = false; + cHighB = false; + lowIndexB = 0; + highIndexB = 0; + lowOverflowB = false; + highOverflowB = false; scrollThresholdA = 0; scrollThresholdB = 0; } int Scroller::scroll(int curA, int curB) { - calculateThresholdA(curA); - calculateThresholdB(curB); + if (lowOverflowA == false || highOverflowA == false) + calculateThresholdA(curA); + if (lowOverflowB == false || highOverflowB == false) + calculateThresholdB(curB); bool LO = false; bool HI = true; @@ -109,36 +126,147 @@ int Scroller::scroll(int curA, int curB) { return ret; } -int Scroller::getScrollThresholdA(void) { - return scrollThresholdA; -} - -int Scroller::al(void) { - return lowA; -} - -int Scroller::ah(void) { - return highA; -} - -int Scroller::getScrollThresholdB(void) { - return scrollThresholdB; -} - int Scroller::calculateThresholdA(int curA) { - if (curA < lowA) - lowA = curA; - else if (curA > highA) - highA = curA; - - scrollThresholdA = ((highA - lowA) / 3) + lowA; + scrollThresholdA = calculateThreshold(curA, lowA, highA, + cLowA, cHighA, arLowA, arHighA, lowIndexA, highIndexA, + lowOverflowA, highOverflowA); } int Scroller::calculateThresholdB(int curB) { - if (curB < lowB) - lowB = curB; - else if (curB > highB) - highB = curB; - - scrollThresholdB = ((highB - lowB) / 3) + lowB; + scrollThresholdB = calculateThreshold(curB, lowB, highB, + cLowB, cHighB, arLowB, arHighB, lowIndexB, highIndexB, + lowOverflowB, highOverflowB); +} + +int Scroller::calculateThreshold(int cur, int &low, int &high, + bool &cLow, bool &cHigh, int arLow[], int arHigh[], + int &lowIndex, int &highIndex, bool &lowOverflow, + bool &highOverflow) { + + if (cur < low) + low = cur; + if (cur > high) + high = cur; + + int curThresh = thresholdEquation(low, high); + int range = high - low; + + // The range is enforced to be over a certain limit because noise + // can cause erroneous readings, making these calculations unstable. + if (range >= THRESH_RANGE_LIM) { + if (cur < curThresh) { + if (cHigh == true) { + // We were just high, and now we crossed to low. + // high reflects a sample of a high reading. + arHigh[highIndex] = high; + incrementIndex(highIndex, highOverflow); + int midpoint = ((high - low) / 2) + low; + low = midpoint; + high = midpoint; + cLow = false; + cHigh = false; + } else { + cLow = true; + } + } if (cur > curThresh) { + if (cLow == true) { + // We were just low, and now we crossed to high. + // low reflects a sample of a low reading. + arLow[lowIndex] = low; + incrementIndex(lowIndex, lowOverflow); + int midpoint = ((high - low) / 2) + low; + low = midpoint; + high = midpoint; + cLow = false; + cHigh = false; + } else { + cHigh = true; + } + } + } + + int calcHigh = 0; + if (highOverflow == true) { + for (int i = 0; i < SCROLLER_AR_SIZE; i++) { + calcHigh += arHigh[i]; + } + calcHigh = calcHigh / SCROLLER_AR_SIZE; + } else if (highIndex != 0) { + for (int i = 0; i < highIndex; i++) { + calcHigh += arHigh[i]; + } + calcHigh = calcHigh / highIndex; + } else { + calcHigh = high; + } + + int calcLow = 0; + if (lowOverflow == true) { + for (int i = 0; i < SCROLLER_AR_SIZE; i++) { + calcLow += arLow[i]; + } + calcLow = calcLow / SCROLLER_AR_SIZE; + } else if (lowIndex != 0) { + for (int i = 0; i < lowIndex; i++) { + calcLow += arLow[i]; + } + calcLow = calcLow / lowIndex; + } else { + calcLow = low; + } + + return thresholdEquation(calcLow, calcHigh); +} + +int Scroller::thresholdEquation(int lo, int hi) { + return ((hi - lo) / 3) + lo; +} + +void Scroller::incrementIndex(int &index, bool &ovflw) { + if (index < SCROLLER_AR_SIZE - 1) + index++; + else { + index = 0; + ovflw = true; + } +} + +void Scroller::debug(void) { + /* + Serial.print(F("lowA: ")); + Serial.print(lowA); + Serial.print(F(", highA: ")); + Serial.print(highA); + Serial.print(F(", cLowA: ")); + Serial.print(cLowA ? "true" : "false"); + Serial.print(F(", cHighA: ")); + Serial.print(cHighA ? "true" : "false"); + Serial.print(F(", lowIndexA: ")); + Serial.print(lowIndexA); + Serial.print(F(", highIndexA: ")); + Serial.print(highIndexA); + Serial.print(F(", lowOverflowA: ")); + Serial.print(lowOverflowA ? "true" : "false"); + Serial.print(F(", highOverflowA: ")); + Serial.println(highOverflowA ? "true" : "false"); + + Serial.print(F("arLowA: ")); + for (int i = 0; i < SCROLLER_AR_SIZE; i++) { + Serial.print(arLowA[i]); + Serial.print(F(",")); + } + Serial.println("."); + + Serial.print(F("arHighA: ")); + for (int i = 0; i < SCROLLER_AR_SIZE; i++) { + Serial.print(arHighA[i]); + Serial.print(F(",")); + } + Serial.println("."); + */ + + Serial.print(F(", thB: ")); + Serial.print(scrollThresholdB); + Serial.print(F(", thA: ")); + Serial.print(scrollThresholdA); } diff --git a/firmware/production/Scroller.h b/firmware/production/Scroller.h index 016a781..9abda0f 100644 --- a/firmware/production/Scroller.h +++ b/firmware/production/Scroller.h @@ -17,30 +17,51 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifndef SCROLLER_AR_SIZE +#define SCROLLER_AR_SIZE 40 +#endif + #ifndef SCROLLER_h #define SCROLLER_h class Scroller { private: + const int THRESH_RANGE_LIM = 10; enum State { HIHI, HILO, LOLO, LOHI }; State state; bool lohif; bool hilof; int lowA; int highA; + bool cLowA; + bool cHighA; + int lowIndexA; + int highIndexA; + bool lowOverflowA; + bool highOverflowA; int lowB; int highB; + bool cLowB; + bool cHighB; + int lowIndexB; + int highIndexB; + bool lowOverflowB; + bool highOverflowB; int scrollThresholdA; int scrollThresholdB; + int arLowA[SCROLLER_AR_SIZE]; + int arHighA[SCROLLER_AR_SIZE]; + int arLowB[SCROLLER_AR_SIZE]; + int arHighB[SCROLLER_AR_SIZE]; int calculateThresholdA(int); int calculateThresholdB(int); + int calculateThreshold(int, int&, int&, bool&, bool&, int*, int*, int&, int&, bool&, bool&); + int thresholdEquation(int, int); + void incrementIndex(int&, bool&); public: Scroller(void); int scroll(int, int); - int getScrollThresholdA(void); - int getScrollThresholdB(void); - int al(void); - int ah(void); + void debug(void); }; #endif diff --git a/firmware/production/production.ino b/firmware/production/production.ino index 56c6a4e..d805e7d 100644 --- a/firmware/production/production.ino +++ b/firmware/production/production.ino @@ -393,15 +393,14 @@ signed char moveWheel() { if (middleButtonPin == LOW) { return 0; } - + lastScroll = micros(); - + int d1 = analogRead(OPT_ENC_PIN1); int d2 = analogRead(OPT_ENC_PIN2); if (debugMode) { - Serial.print(F("th: ")); - Serial.print(scroller.getScrollThreshold()); + scroller.debug(); Serial.print(F(", d1: ")); Serial.print(d1); Serial.print(F(", d2: "));