mirror of
https://github.com/skogaby/OpeNITHM.git
synced 2026-09-22 22:58:16 +03:00
Experimenting with different autocalibration. WIP
This commit is contained in:
@@ -61,21 +61,18 @@ void AutoTouchboard::calibrateKeys()
|
||||
}
|
||||
|
||||
// Take the initial baseline readings so we can populate our delta buffer
|
||||
int value;
|
||||
scan();
|
||||
|
||||
for (int r = 0; r < NUM_READINGS; r++) {
|
||||
scan();
|
||||
|
||||
for (int i = 0; i < NUM_SENSORS; i++) {
|
||||
value = key_values[i];
|
||||
|
||||
// calculate the newest delta if it's not the first reading
|
||||
if (r > 0) {
|
||||
deltas[i]->addValue(value - lastReadings[i]);
|
||||
}
|
||||
|
||||
lastReadings[i] = value;
|
||||
}
|
||||
int value;
|
||||
// take some initial readings before the main loop so we can establish baselines
|
||||
for (int i = 0; i < NUM_SENSORS; i++) {
|
||||
// determine the current thresholds for trigger
|
||||
// and release based on the configured delta threhsold
|
||||
// and the current readings
|
||||
value = key_values[i];
|
||||
|
||||
states[i] = UNPRESSED;
|
||||
calcThresholds(i, value);
|
||||
}
|
||||
|
||||
// Flash the slider green for a couple of seconds to show success
|
||||
@@ -96,51 +93,35 @@ KeyState AutoTouchboard::update(int key)
|
||||
{
|
||||
// check if the button is pressed
|
||||
// keep a running record of the last X deltas and the latest readings
|
||||
int value = key_values[key];
|
||||
deltas[key]->addValue(value - lastReadings[key]);
|
||||
lastReadings[key] = value;
|
||||
bool deltaTriggered = (deltas[key]->getSum() > deltaThreshold);
|
||||
int pressure = key_values[key];
|
||||
unsigned long currMillis = millis();
|
||||
|
||||
if (states[key] == UNPRESSED) {
|
||||
// new press detected
|
||||
if (pressure > triggerThresholdsDouble[key]) {
|
||||
lastTriggerTimes[key] = currMillis;
|
||||
states[key] = DOUBLE_PRESS;
|
||||
} else if (pressure > triggerThresholdsSingle[key]) {
|
||||
lastTriggerTimes[key] = currMillis;
|
||||
states[key] = SINGLE_PRESS;
|
||||
// the key hasn't been triggered, so we'll check how long it's been since
|
||||
// the last trigger. if it's been more than the configured period, re-establish
|
||||
// baselines for thresholds
|
||||
} else if (currMillis - lastTriggerTimes[key] > CALIBRATION_PERIOD) {
|
||||
calcThresholds(key, pressure);
|
||||
}
|
||||
// new release detected
|
||||
} else if (states[key] != UNPRESSED) {
|
||||
if (pressure < releaseThresholdsSingle[key]) {
|
||||
states[key] = UNPRESSED;
|
||||
} else if (pressure < releaseThresholdsDouble[key]) {
|
||||
states[key] = SINGLE_PRESS;
|
||||
}
|
||||
}
|
||||
|
||||
#if NUM_SENSORS == 32
|
||||
// check the readout data and the running sum of the deltas;
|
||||
// if running sum of deltas goes above our defined threshold,
|
||||
// trigger a press and set new lower bounds for release,
|
||||
// otherwise, check for a release
|
||||
if (states[key] == UNPRESSED && deltaTriggered) {
|
||||
// set a new release threshold based on the reading at the time we detected
|
||||
// the press (minus the threshold + a small hysteresis factor)
|
||||
releaseThresholdsSingle[key] = value - deltaThreshold + releaseHysteresis;
|
||||
states[key] = SINGLE_PRESS;
|
||||
} else if (states[key] != UNPRESSED && (value < releaseThresholdsSingle[key])) {
|
||||
// new release
|
||||
states[key] = UNPRESSED;
|
||||
releaseThresholdsSingle[key] = 0;
|
||||
}
|
||||
#elif NUM_SENSORS == 16
|
||||
// check for new single press
|
||||
if (states[key] == UNPRESSED && deltaTriggered) {
|
||||
// set a new single release threshold based on the reading at the time we detected
|
||||
// the press (minus the threshold + a small hysteresis factor)
|
||||
releaseThresholdsSingle[key] = value - deltaThreshold + releaseHysteresis;
|
||||
states[key] = SINGLE_PRESS;
|
||||
}
|
||||
// check for new double press
|
||||
else if (states[key] == SINGLE_PRESS && deltaTriggered) {
|
||||
// set a new release threshold based on the reading at the time we detected
|
||||
// the press (minus the threshold + a small hysteresis factor)
|
||||
releaseThresholdsDouble[key] = value - deltaThreshold + releaseHysteresis;
|
||||
states[key] = DOUBLE_PRESS;
|
||||
}
|
||||
// check for double -> single release
|
||||
else if (states[key] == DOUBLE_PRESS && (value < releaseThresholdsDouble[key]) && (value > releaseThresholdsSingle[key])) {
|
||||
states[key] = SINGLE_PRESS;
|
||||
releaseThresholdsDouble[key] = 0;
|
||||
}
|
||||
// check for any press (single or double) to no press)
|
||||
else if (states[key] != UNPRESSED && value < releaseThresholdsSingle[key]) {
|
||||
states[key] = UNPRESSED;
|
||||
releaseThresholdsSingle[key] = 0;
|
||||
releaseThresholdsDouble[key] = 0;
|
||||
if (states[key] == DOUBLE_PRESS) {
|
||||
states[key] == SINGLE_PRESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -152,16 +133,20 @@ uint16_t AutoTouchboard::getRawValue(int key)
|
||||
return key_values[key];
|
||||
}
|
||||
|
||||
void AutoTouchboard::calcThresholds(int key, int pressure)
|
||||
{
|
||||
triggerThresholdsSingle[key] = pressure + deltaThreshold;
|
||||
releaseThresholdsSingle[key] = pressure + (deltaThreshold * releaseThreshold);
|
||||
triggerThresholdsDouble[key] = triggerThresholdsSingle[key] + (0.8 * deltaThreshold);
|
||||
releaseThresholdsDouble[key] = triggerThresholdsSingle[key] + (0.8 * deltaThreshold * releaseThreshold);
|
||||
lastTriggerTimes[key] = millis();
|
||||
}
|
||||
|
||||
AutoTouchboard::AutoTouchboard()
|
||||
{
|
||||
pinMode(MUX_0, OUTPUT);
|
||||
pinMode(MUX_1, OUTPUT);
|
||||
pinMode(MUX_2, OUTPUT);
|
||||
|
||||
for (int i = 0; i < NUM_SENSORS; i++) {
|
||||
deltas[i] = new RunningSum(NUM_READINGS);
|
||||
states[i] = UNPRESSED;
|
||||
}
|
||||
|
||||
|
||||
calibrateKeys();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "Config.h"
|
||||
#include "PinConfig.h"
|
||||
#include "RunningSum.h"
|
||||
#include "USBOutput.h"
|
||||
|
||||
#include <EEPROM.h>
|
||||
@@ -26,8 +25,7 @@ extern CRGB leds[16];
|
||||
extern CRGB leds[31];
|
||||
#endif
|
||||
|
||||
// the size of the buffer of deltas to keep for each key
|
||||
#define NUM_READINGS 10
|
||||
#define CALIBRATION_PERIOD 15000
|
||||
|
||||
class AutoTouchboard
|
||||
{
|
||||
@@ -35,18 +33,20 @@ class AutoTouchboard
|
||||
// these will be tunable / need to be experimented with
|
||||
#if NUM_SENSORS == 32
|
||||
int deltaThreshold = 4;
|
||||
int releaseHysteresis = 1;
|
||||
double releaseThreshold = 0.8;
|
||||
#else
|
||||
int deltaThreshold = 6;
|
||||
int releaseHysteresis = 2;
|
||||
double releaseThreshold = 0.8;
|
||||
#endif
|
||||
|
||||
uint16_t key_values[NUM_SENSORS];
|
||||
KeyState states[NUM_SENSORS];
|
||||
int triggerThresholdsSingle[NUM_SENSORS];
|
||||
int releaseThresholdsSingle[NUM_SENSORS];
|
||||
int triggerThresholdsDouble[NUM_SENSORS];
|
||||
int releaseThresholdsDouble[NUM_SENSORS];
|
||||
int lastReadings[NUM_SENSORS];
|
||||
RunningSum* deltas[NUM_SENSORS];
|
||||
unsigned long lastTriggerTimes[NUM_SENSORS];
|
||||
void calcThresholds(int key, int pressure);
|
||||
|
||||
public:
|
||||
AutoTouchboard();
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#include "RunningSum.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
RunningSum::RunningSum(int n) {
|
||||
_size = n;
|
||||
_ar = (int*) malloc(_size * sizeof(int));
|
||||
if (_ar == NULL) _size = 0;
|
||||
clear();
|
||||
}
|
||||
|
||||
RunningSum::~RunningSum() {
|
||||
if (_ar != NULL) free(_ar);
|
||||
}
|
||||
|
||||
void RunningSum::clear() {
|
||||
_cnt = 0;
|
||||
_idx = 0;
|
||||
_sum = 0.0;
|
||||
for (int i = 0; i< _size; i++) _ar[i] = 0;
|
||||
}
|
||||
|
||||
void RunningSum::addValue(int f) {
|
||||
if (_ar == NULL) return;
|
||||
_sum -= _ar[_idx];
|
||||
_ar[_idx] = f;
|
||||
_sum += f;
|
||||
_idx++;
|
||||
if (_idx == _size) _idx = 0;
|
||||
if (_cnt < _size) _cnt++;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#ifndef RunningSum_h
|
||||
#define RunningSum_h
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
class RunningSum
|
||||
{
|
||||
public:
|
||||
RunningSum(void);
|
||||
RunningSum(int);
|
||||
~RunningSum();
|
||||
|
||||
void clear();
|
||||
void addValue(int);
|
||||
|
||||
uint8_t getCount() { return _cnt; }
|
||||
int getSum() { return _sum; }
|
||||
|
||||
protected:
|
||||
uint8_t _size;
|
||||
uint8_t _cnt;
|
||||
uint8_t _idx;
|
||||
int _sum;
|
||||
int * _ar;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user