Skip to content

Commit

Permalink
Refactor Touch class to extract Brush and Rub classes as their own to…
Browse files Browse the repository at this point in the history
…uch features
  • Loading branch information
vberthiaume committed Jan 8, 2025
1 parent f19ab5f commit 2d00e5f
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 137 deletions.
7 changes: 3 additions & 4 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ jobs:
}
- {
os: windows-latest,
cmake_options: "BOOST_ROOT=c:/local/boost_1_86_0",
dependencies: "choco install eigen -y --no-progress && choco install boost-msvc-14.3 -y --no-progress"
cmake_options: "Boost_INCLUDE_DIR=D:/a/puara-gestures/puara-gestures/3rdparty",
dependencies: "choco install eigen -y --no-progress"
}

runs-on: ${{ matrix.config.os }}
Expand All @@ -31,12 +31,11 @@ jobs:
submodules: recursive

- name: Dependencies
run: ${{ matrix.config.dependencies }}
run: ${{ matrix.config.dependencies }}

- name: Build Project
uses: threeal/[email protected]
with:
options: |
PUARA_GESTURES_ENABLE_STANDALONE=0
${{ matrix.config.cmake_options }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ build/
*.user
*code-workspace
.pio
exampleProjects/touch/.gitignore
2 changes: 1 addition & 1 deletion 3rdparty
Submodule 3rdparty updated 1 files
+1 −1 IMU_Sensor_Fusion
1 change: 1 addition & 0 deletions exampleProjects/touch/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ build_flags =
-I../../include/
-I../../3rdparty/
-std=gnu++2a
; -O0
build_unflags =
-std=gnu++11
-std=gnu++14
Expand Down
37 changes: 24 additions & 13 deletions include/puara/descriptors/jab.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ namespace puara_gestures
*
* It expects 1 axis of a accelerometer in m/s^2, but can be used
* with any double or float.
*
* Jab can use `tied_data`, which is an external variable that users update on their own.
* Users can then call update() without any argumments to extract the features from the `tied_data`.
* The usage should be:
* setup:
* - user creates variable, e.g. sensor_data
* user instantiates the class, e.g. puara::jab my_jab(sensor_data)
* loop/task:
* - user saves sensor value into sensor_data
* - user/task calls my_jab.update()
* - user accesses jab value with my_jab.current_value()
*/
class Jab
{
Expand All @@ -26,8 +37,7 @@ class Jab

Jab() noexcept
: threshold(5)
, tied_value(nullptr)
, minmax(10)
, tied_data(nullptr)
{
}

Expand All @@ -38,21 +48,19 @@ class Jab

explicit Jab(double* tied)
: threshold(5)
, tied_value(tied)
, minmax(10)
, tied_data(tied)
{
}

explicit Jab(Coord1D* tied)
: threshold(5)
, tied_value(&(tied->x))
, minmax(10)
, tied_data(&(tied->x))
{
}

double update(double reading)
double update(double data)
{
minmax.update(reading);
minmax.update(data);
double min = minmax.current_value.min;
double max = minmax.current_value.max;

Expand Down Expand Up @@ -82,13 +90,14 @@ class Jab

int update()
{
if(tied_value != nullptr)
if(tied_data != nullptr)
{
Jab::update(*tied_value);
Jab::update(*tied_data);
return 1;
}
else
{
// should we assert here, it seems like an error to call update() without a tied_value?
return 0;
}
}
Expand All @@ -97,14 +106,16 @@ class Jab

int tie(Coord1D* new_tie)
{
tied_value = &(new_tie->x);
tied_data = &(new_tie->x);
return 1;
}

private:
double* tied_value{};
const double* tied_data{};
double value = 0;
puara_gestures::utils::RollingMinMax<double> minmax;

/** Keep track of the min and max values over the last 10 times Jab::update() was called. */
puara_gestures::utils::RollingMinMax<double> minmax{};
};

/**
Expand Down
146 changes: 28 additions & 118 deletions include/puara/descriptors/touch.h
Original file line number Diff line number Diff line change
@@ -1,144 +1,54 @@
#pragma once

#include <puara/utils.h>
#include <puara/utils/blobDetector.h>
#include <puara/utils/leakyintegrator.h>

#include <cmath>
#include<iostream>
#include "touchFeatures.h"

namespace puara_gestures
{

class Touch
{
public:
static constexpr int maxNumBlobs = BlobDetector::maxNumBlobs;
float touchAll = 0.0f; // f, 0--1
float touchTop = 0.0f; // f, 0--1
float touchMiddle = 0.0f; // f, 0--1
float touchBottom = 0.0f; // f, 0--1
float brush = 0.0f; // f, 0--? (~cm/s)
double multiBrush[maxNumBlobs]{}; // ffff, 0--? (~cm/s)
float rub{}; // f, 0--? (~cm/s)
double multiRub[maxNumBlobs]{}; // ffff, 0--? (~cm/s)
static constexpr auto touchSizeEdge{4}; // amount of stripes for top and bottom portions (arbitrary)

// touch array
int touchSizeEdge = 4; // amount of touch stripes for top and bottom portions (arbitrary)
float touchAll{}; // f, 0--1
float touchTop{}; // f, 0--1
float touchMiddle{}; // f, 0--1
float touchBottom{}; // f, 0--1

BlobDetector blobDetector;
int brushCounter[maxNumBlobs]{};
/** brush: direction and intensity of capsense brush motion in ~cm/s (distance between stripes = ~1.5cm) */
float brush{};
Brush brushes[maxNumBlobs];

// Arrays of LeakyIntegrator instances
utils::LeakyIntegrator multiBrushIntegrator[maxNumBlobs];
utils::LeakyIntegrator multiRubIntegrator[maxNumBlobs];
/** rub: intensity of rub motion in ~cm/s (distance between stripes = ~1.5cm) */
float rub{};
Rub rubs[maxNumBlobs];

Touch()
{
for(int i = 0; i < maxNumBlobs; ++i)
{
multiBrushIntegrator[i] = utils::LeakyIntegrator(0.0f, 0.0f, 0.7f, 100, 0);
multiRubIntegrator[i] = utils::LeakyIntegrator(0.0f, 0.0f, 0.7f, 100, 0);
}
}
BlobDetector blobDetector;

/* Expects an array of discrete touch values (int, 0 or 1) and
* the size of the array
*/
void updateTouchArray(int* discrete_touch, int touchSize)
{ // raw_touch

// touchAll: get the "amount of touch" for the entire touch sensor
// normalized between 0 and 1
touchAll = touchAverage(discrete_touch, 0, touchSize);

// touchTop: get the "amount of touch" for the top part of the capsense
// normalized between 0 and 1
touchTop = touchAverage(discrete_touch, 0, touchSizeEdge);

// touchMiddle: get the "amount of touch" for the central part of the capsense
// normalized between 0 and 1
touchMiddle
= touchAverage(discrete_touch, (0 + touchSizeEdge), (touchSize - touchSizeEdge));

// touchBottom: get the "amount of touch" for the botton part of the capsense
// normalized between 0 and 1
touchBottom = touchAverage(discrete_touch, (touchSize - touchSizeEdge), touchSize);

// 1D blob detection: used for brush
const auto movement = blobDetector.detect1D(discrete_touch, touchSize);

// brush: direction and intensity of capsense brush motion
// rub: intensity of rub motion
// in ~cm/s (distance between stripes = ~1.5cm)
for(int i = 0; i < movement.size(); ++i)
{
// Update the "amount of touch" for the entire touch sensor, as well as the top, middle and bottom parts.
// All normalized between 0 and 1.
touchAll = utils::arrayAverage(discrete_touch, 0, touchSize);
touchTop = utils::arrayAverage(discrete_touch, 0, touchSizeEdge);
touchMiddle = utils::arrayAverage(discrete_touch, (0 + touchSizeEdge), (touchSize - touchSizeEdge));
touchBottom = utils::arrayAverage(discrete_touch, (touchSize - touchSizeEdge), touchSize);

const auto blobMovements{blobDetector.detect1D(discrete_touch, touchSize)};
for(int i = 0; i < maxNumBlobs; ++i)
{
if(movement[i] == 0)
{
if(brushCounter[i] < 10)
{
brushCounter[i]++;
// wait some time before dropping the rub/brush values
}
else if(multiBrush[i] < 0.001)
{
multiBrush[i] = 0;
multiRub[i] = 0;
}
else
{
// multiBrush[i] = multiBrushIntegrator[i].integrate(
// movement * 0.15, multiBrush[i], 0.7, leakyBrushFreq, leakyBrushTimer);

// multiRub[i] = multiRubIntegrator[i].integrate(
// (std::abs(movement * 0.15)), multiRub[i], 0.7, leakyRubFreq,
// leakyRubTimer);
//
multiBrush[i] = multiBrushIntegrator[i].integrate(movement[i] * 0.15);
multiRub[i] = multiRubIntegrator[i].integrate(std::abs(movement[i] * 0.15));
}
}
else if(std::abs(movement[i]) > 1)
{
// multiBrush[i] = multiBrushIntegrator[i].integrate(
// 0, multiBrush[i], 0.6, leakyBrushFreq, leakyBrushTimer);

multiBrush[i] = multiBrushIntegrator[i].integrate(0);
}
else
{
// multiBrush[i] = multiBrushIntegrator[i].integrate(
// movement * 0.15, multiBrush[i], 0.8, leakyBrushFreq, leakyBrushTimer);
// multiRub[i] = multiRubIntegrator[i].integrate(
// (std::abs(movement * 0.15)) * 0.15, multiRub[i], 0.99, leakyRubFreq,
// leakyRubTimer);

multiBrush[i] = multiBrushIntegrator[i].integrate(movement[i] * 0.15);
multiRub[i] = multiRubIntegrator[i].integrate((std::abs(movement[i] * 0.15)));

brushCounter[i] = 0;
}
brushes[i].update(blobMovements[i]);
rubs[i].update(blobMovements[i]);
}
brush = utils::arrayAverageZero(multiBrush, maxNumBlobs);
rub = utils::arrayAverageZero(multiRub, maxNumBlobs);
}

float touchAverage(float* touchArrayStrips, int firstStrip, int lastStrip)
{
int sum = 0;
for(int i = firstStrip; i < lastStrip - 1; ++i)
sum += touchArrayStrips[i];

return ((float)sum) / (lastStrip - firstStrip);
}

float touchAverage(int* touchArrayStrips, int firstStrip, int lastStrip)
{
int sum = 0;
for(int i = firstStrip; i < lastStrip; i++)
sum += (float)touchArrayStrips[i];

return ((float)sum) / (lastStrip - firstStrip);
// Calculate total brush and rub values
brush = utils::arrayAverageZero(brushes, maxNumBlobs);
rub = utils::arrayAverageZero(rubs, maxNumBlobs);
}
};
}
Loading

0 comments on commit 2d00e5f

Please sign in to comment.