Sitelet https://github.com/akomakom/esp32-spa-controller/commit/56069443724bdb90c5bdfac436a550d8ef0e92e5
Skip to content

Commit 5606944

Browse files
committed
touch accuracy by averaging
1 parent e1afd1e commit 5606944

2 files changed

Lines changed: 63 additions & 6 deletions

File tree

‎display/lv_conf.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
#define LV_DISP_DEF_REFR_PERIOD 30 /*[ms]*/
8282

8383
/*Input device read period in milliseconds*/
84-
#define LV_INDEV_DEF_READ_PERIOD 30 /*[ms]*/
84+
#define LV_INDEV_DEF_READ_PERIOD 15 /*[ms]*/ /*lowered from 30: more touch samples per tap for the median filter (see touch.h)*/
8585

8686
/*Use a custom tick source that tells the elapsed time in milliseconds.
8787
*It removes the need to manually update the tick with `lv_tick_inc()`)*/

‎display/touch.h‎

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,37 @@ TAMC_GT911 ts = TAMC_GT911(TOUCH_GT911_SDA, TOUCH_GT911_SCL, TOUCH_GT911_INT, TO
6767
#include <SPI.h>
6868
XPT2046_Touchscreen ts(TOUCH_XPT2046_CS, TOUCH_XPT2046_INT);
6969

70+
// --- Rolling-median filter -----------------------------------------------------
71+
// This resistive panel occasionally returns a wildly off raw reading (a single
72+
// sample can jump 30%+, e.g. raw X 1304 among neighbours around 850), which then
73+
// maps onto the wrong control. Each physical touch yields several samples, so keep
74+
// a short window of raw readings and report their per-axis MEDIAN, which discards
75+
// the odd outlier (a mean would still be dragged toward it). A gap since the last
76+
// sample starts a fresh window (= a new, separate touch). We withhold the press
77+
// until a few samples are in, so the very first (possibly bad) sample can't land
78+
// the press on the wrong control.
79+
#define TOUCH_MEDIAN_WINDOW 7 // raw samples retained
80+
#define TOUCH_MEDIAN_MIN 3 // samples for the normal path (median rejects 1 outlier)
81+
#define TOUCH_MEDIAN_FLOOR 2 // fewest samples the time fallback will accept
82+
#define TOUCH_SETTLE_MS 45 // commit a short touch by now even with < MIN samples
83+
#define TOUCH_NEW_TOUCH_GAP_MS 120 // gap that marks the start of a new touch
84+
static int touchRawX[TOUCH_MEDIAN_WINDOW];
85+
static int touchRawY[TOUCH_MEDIAN_WINDOW];
86+
static uint8_t touchSampleCount = 0;
87+
static uint8_t touchSampleHead = 0;
88+
static unsigned long touchLastSampleMs = 0;
89+
static unsigned long touchStartMs = 0; // time of the first sample of the current touch
90+
91+
static int touch_median(const int *src, uint8_t n) {
92+
int tmp[TOUCH_MEDIAN_WINDOW];
93+
for (uint8_t i = 0; i < n; i++) tmp[i] = src[i];
94+
for (uint8_t i = 1; i < n; i++) { // insertion sort; n is tiny (<= window)
95+
int v = tmp[i], j = i;
96+
while (j > 0 && tmp[j - 1] > v) { tmp[j] = tmp[j - 1]; j--; }
97+
tmp[j] = v;
98+
}
99+
return tmp[n / 2];
100+
}
70101
#endif
71102

72103
#if defined(TOUCH_FT6X36)
@@ -184,13 +215,39 @@ bool touch_touched()
184215
if (ts.touched())
185216
{
186217
TS_Point p = ts.getPoint();
187-
Serial.printf("Touch Raw remap from %d/%d @%d", p.x, p.y, p.z);
218+
219+
unsigned long nowMs = millis();
220+
if (nowMs - touchLastSampleMs > TOUCH_NEW_TOUCH_GAP_MS) {
221+
// Long gap since the last sample -> this is a new touch; drop the old window.
222+
touchSampleCount = 0;
223+
touchSampleHead = 0;
224+
touchStartMs = nowMs;
225+
}
226+
touchLastSampleMs = nowMs;
227+
228+
touchRawX[touchSampleHead] = p.x;
229+
touchRawY[touchSampleHead] = p.y;
230+
touchSampleHead = (touchSampleHead + 1) % TOUCH_MEDIAN_WINDOW;
231+
if (touchSampleCount < TOUCH_MEDIAN_WINDOW) touchSampleCount++;
232+
233+
// Commit the press once we have enough samples for a solid median, OR after a
234+
// short settle time with at least a couple of samples (so a brief tap that only
235+
// produces 2 reads still registers instead of being silently dropped).
236+
bool ready = (touchSampleCount >= TOUCH_MEDIAN_MIN) ||
237+
(touchSampleCount >= TOUCH_MEDIAN_FLOOR && (nowMs - touchStartMs) >= TOUCH_SETTLE_MS);
238+
if (!ready) {
239+
return false;
240+
}
241+
242+
int mx = touch_median(touchRawX, touchSampleCount);
243+
int my = touch_median(touchRawY, touchSampleCount);
244+
Serial.printf("Touch raw %d/%d @%d -> median %d/%d (n=%d)", p.x, p.y, p.z, mx, my, touchSampleCount);
188245
#if defined(TOUCH_SWAP_XY)
189-
touch_last_x = map(p.y, TOUCH_MAP_X1, TOUCH_MAP_X2, 0, gfx->width() - 1);
190-
touch_last_y = map(p.x, TOUCH_MAP_Y1, TOUCH_MAP_Y2, 0, gfx->height() - 1);
246+
touch_last_x = map(my, TOUCH_MAP_X1, TOUCH_MAP_X2, 0, gfx->width() - 1);
247+
touch_last_y = map(mx, TOUCH_MAP_Y1, TOUCH_MAP_Y2, 0, gfx->height() - 1);
191248
#else
192-
touch_last_x = map(p.x, TOUCH_MAP_X1, TOUCH_MAP_X2, 0, gfx->width() - 1);
193-
touch_last_y = map(p.y, TOUCH_MAP_Y1, TOUCH_MAP_Y2, 0, gfx->height() - 1);
249+
touch_last_x = map(mx, TOUCH_MAP_X1, TOUCH_MAP_X2, 0, gfx->width() - 1);
250+
touch_last_y = map(my, TOUCH_MAP_Y1, TOUCH_MAP_Y2, 0, gfx->height() - 1);
194251
#endif
195252
return true;
196253
}

0 commit comments

Comments
 (0)