From 07ca931b255c18dd8f705364323adb3b3662daa8 Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Thu, 11 May 2023 23:37:38 +0400 Subject: [PATCH 01/16] feat(OpenGloves): add finger initialization --- .github/workflows/ci.yml | 11 ++- .../mode_configs/opengloves/opengloves.cpp | 75 +++++++++++++++++++ ini/opengloves.ini | 47 ++++++++++++ lib/arduino/sensor/joystick.hpp | 37 +++++++++ lib/opengloves/og_constants.hpp | 3 + lib/opengloves/sensor/og_finger.hpp | 41 ++++++++++ lib/sensor/sensor.hpp | 2 +- platformio.ini | 1 + 8 files changed, 214 insertions(+), 3 deletions(-) create mode 100644 firmware/mode_configs/opengloves/opengloves.cpp create mode 100644 ini/opengloves.ini create mode 100644 lib/arduino/sensor/joystick.hpp create mode 100644 lib/opengloves/og_constants.hpp create mode 100644 lib/opengloves/sensor/og_finger.hpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fc7a02a..6ec8db0f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ on: - '**/*.md' jobs: - build: + build-bhaptics: name: Build ${{ matrix.target }} on ${{ matrix.os }} ${{ matrix.coverage && 'with coverage' || 'without coverage' }}, -D ${{ matrix.battery_flag }} -D ${{ matrix.serial_plotter_flag }} -D ${{ matrix.nimble_flag }} runs-on: ${{ matrix.os }} strategy: @@ -58,6 +58,10 @@ jobs: serial_plotter_flag: SERIAL_PLOTTER=false nimble_flag: BLUETOOTH_USE_NIMBLE=true + - target: opengloves + os: ubuntu-latest + coverage: true + steps: - uses: actions/checkout@v3 @@ -214,7 +218,10 @@ jobs: retention-days: 5 coverage-report: - needs: [build, test] + needs: + - build-bhaptics + # - build-opengloves + - test runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp new file mode 100644 index 00000000..28fbcba3 --- /dev/null +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include + +#define CALIBRATION_CURL OH::MinMaxCalibrator + +#define FINGER_THUMB_ENABLED (PIN_FINGER_THUMB != -1) +#define FINGER_INDEX_ENABLED (PIN_FINGER_INDEX != -1) +#define FINGER_MIDDLE_ENABLED (PIN_FINGER_MIDDLE != -1) +#define FINGER_RING_ENABLED (PIN_FINGER_RING != -1) +#define FINGER_PINKY_ENABLED (PIN_FINGER_PINKY != -1) +#define FINGER_COUNT (FINGER_THUMB_ENABLED + FINGER_INDEX_ENABLED + FINGER_MIDDLE_ENABLED + FINGER_RING_ENABLED + FINGER_PINKY_ENABLED) + +#define JOYSTICK_ENABLED (PIN_JOYSTICK_X != -1 && PIN_JOYSTICK_Y != -1) +#define JOYSTICK_COUNT (JOYSTICK_ENABLED ? 2 : 0) + +using namespace OpenGloves; + +#pragma region FingerSensor + +#if FINGER_THUMB_ENABLED + auto* fingerThumb = new FingerSensor(PIN_FINGER_THUMB, FINGER_THUMB_INVERT, new CALIBRATION_CURL()); +#endif + +#if FINGER_INDEX_ENABLED + auto* fingerIndex = new FingerSensor(PIN_FINGER_INDEX, FINGER_INDEX_INVERT, new CALIBRATION_CURL()); +#endif + +#if FINGER_MIDDLE_ENABLED + auto* fingerMiddle = new FingerSensor(PIN_FINGER_MIDDLE, FINGER_MIDDLE_INVERT, new CALIBRATION_CURL()); +#endif + +#if FINGER_RING_ENABLED + auto* fingerRing = new FingerSensor(PIN_FINGER_RING, FINGER_RING_INVERT, new CALIBRATION_CURL()); +#endif + +#if FINGER_PINKY_ENABLED + auto* fingerPinky = new FingerSensor(PIN_FINGER_PINKY, FINGER_PINKY_INVERT, new CALIBRATION_CURL()); +#endif + +IFinger* fingers[FINGER_COUNT] = { +#if FINGER_THUMB_ENABLED + fingerThumb, +#endif +#if FINGER_INDEX_ENABLED + fingerIndex, +#endif +#if FINGER_MIDDLE_ENABLED + fingerMiddle, +#endif +#if FINGER_RING_ENABLED + fingerRing, +#endif +#if FINGER_PINKY_ENABLED + fingerPinky, +#endif +}; + +#pragma endregion + +OH::JoystickAxisSensor* joystick[] = { +#if JOYSTICK_ENABLED + new OH::JoystickAxisSensor(PIN_JOYSTICK_X, JOYSTICK_DEADZONE, JOYSTICK_X_INVERT), + new OH::JoystickAxisSensor(PIN_JOYSTICK_Y, JOYSTICK_DEADZONE, JOYSTICK_Y_INVERT), +#endif +}; + +void setupMode() { + +} + +void loopMode() { + +} diff --git a/ini/opengloves.ini b/ini/opengloves.ini new file mode 100644 index 00000000..9c4dcca1 --- /dev/null +++ b/ini/opengloves.ini @@ -0,0 +1,47 @@ +[opengloves] +platform = platformio/espressif32@^6.1.0 +platform_packages = + platformio/framework-arduinoespressif32@^3.20007.0 +framework = arduino +board = esp32doit-devkit-v1 +upload_speed = 921600 +monitor_speed = 115200 + +build_flags = ${common.build_flags} + -D OPENGLOVES + -D FINGER_THUMB_INVERT=false + -D FINGER_INDEX_INVERT=false + -D FINGER_MIDDLE_INVERT=false + -D FINGER_RING_INVERT=false + -D FINGER_PINKY_INVERT=false + + -D JOYSTICK_X_INVERT=false + -D JOYSTICK_Y_INVERT=false + -D JOYSTICK_DEADZONE=0.1 + + ; Pins configuration + ; If pin set to -1, then it will be ignored + -D PIN_FINGER_THUMB=32 + -D PIN_FINGER_INDEX=35 + -D PIN_FINGER_MIDDLE=34 + -D PIN_FINGER_RING=39 + -D PIN_FINGER_PINKY=36 + -D PIN_JOYSTICK_X=33 + -D PIN_JOYSTICK_Y=25 +build_unflags = ${common.build_unflags} +build_src_filter = ${common.build_src_filter} +lib_deps = ${common.lib_deps} + +[env:opengloves] +platform = ${opengloves.platform} +platform_packages = ${opengloves.platform_packages} +framework = ${opengloves.framework} +board = ${opengloves.board} +upload_speed = ${opengloves.upload_speed} +monitor_speed = ${opengloves.monitor_speed} + +build_flags = ${opengloves.build_flags} +build_unflags = ${opengloves.build_unflags} +build_src_filter = ${opengloves.build_src_filter} + + +lib_deps = ${opengloves.lib_deps} diff --git a/lib/arduino/sensor/joystick.hpp b/lib/arduino/sensor/joystick.hpp new file mode 100644 index 00000000..bcc2b271 --- /dev/null +++ b/lib/arduino/sensor/joystick.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include + +namespace OH { + class JoystickAxisSensor : public ISensor { + private: + uint8_t pin; + float dead_zone; + bool invert; + + int filterDeadZone(int in) { + // This function clamps the input to the center of the range if + // the value is within the threshold. This is to eliminate at-rest + // noise of the joystick. + int center = ANALOG_MAX / 2; + return abs(center - in) < dead_zone * ANALOG_MAX ? center : in; + } + + protected: + uint16_t getValue(void) override { + auto value = analogRead(this->pin); + value = this->filterDeadZone(value); + + if (this->invert) { + value = ANALOG_MAX - value; + } + + return value; + } + + public: + JoystickAxisSensor(uint8_t pin, float dead_zone, bool invert = false) : pin(pin), dead_zone(dead_zone), invert(invert) {} + }; +}; // namespace OH diff --git a/lib/opengloves/og_constants.hpp b/lib/opengloves/og_constants.hpp new file mode 100644 index 00000000..fc9712b7 --- /dev/null +++ b/lib/opengloves/og_constants.hpp @@ -0,0 +1,3 @@ +#pragma once + +#define OPENGLOVES_FINGERS_TASK_PRIORITY 1 diff --git a/lib/opengloves/sensor/og_finger.hpp b/lib/opengloves/sensor/og_finger.hpp new file mode 100644 index 00000000..e1eca696 --- /dev/null +++ b/lib/opengloves/sensor/og_finger.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +#include + +namespace OpenGloves +{ + struct IFinger { + // + }; + + class FingerSensor : public IFinger, public OH::CalibratedSensor + { + private: + uint8_t pin; + bool invert; + + protected: + uint16_t updateValue(void) override { + auto value = analogRead(this->pin); + + if (this->invert) { + value = ANALOG_MAX - value; + } + + // TODO: add median filter + + return value; + }; + + public: + FingerSensor(uint8_t pin, bool invert, OH::Calibrator* calibrator) : + OH::CalibratedSensor(calibrator), + pin(pin), invert(invert) {}; + }; + + // TODO: add splay finger sensor + +} // namespace OpenGloves diff --git a/lib/sensor/sensor.hpp b/lib/sensor/sensor.hpp index e34b26be..a1ce2043 100644 --- a/lib/sensor/sensor.hpp +++ b/lib/sensor/sensor.hpp @@ -102,7 +102,7 @@ namespace OH }; void resetCalibration() override { - calibrator.reset(); + calibrator->reset(); } }; } // namespace OH diff --git a/platformio.ini b/platformio.ini index 61b31ea2..558b10a8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -14,6 +14,7 @@ lib_dir = ./lib src_dir = ./firmware extra_configs = ini/bhaptics.ini + ini/opengloves.ini [common] build_unflags = From cf33c867f37a02b734a6c0f61f9852219c14444c Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Tue, 6 Jun 2023 20:37:49 +0400 Subject: [PATCH 02/16] feat(OpenGloves): setup components on init [skip ci] --- firmware/mode_configs/opengloves/opengloves.cpp | 10 ++++++++-- lib/arduino/sensor/joystick.hpp | 4 ++++ lib/opengloves/sensor/og_finger.hpp | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp index 28fbcba3..359c78e6 100644 --- a/firmware/mode_configs/opengloves/opengloves.cpp +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -39,7 +39,7 @@ using namespace OpenGloves; auto* fingerPinky = new FingerSensor(PIN_FINGER_PINKY, FINGER_PINKY_INVERT, new CALIBRATION_CURL()); #endif -IFinger* fingers[FINGER_COUNT] = { +FingerSensor* fingers[FINGER_COUNT] = { #if FINGER_THUMB_ENABLED fingerThumb, #endif @@ -59,7 +59,7 @@ IFinger* fingers[FINGER_COUNT] = { #pragma endregion -OH::JoystickAxisSensor* joystick[] = { +OH::JoystickAxisSensor* joystick[JOYSTICK_COUNT] = { #if JOYSTICK_ENABLED new OH::JoystickAxisSensor(PIN_JOYSTICK_X, JOYSTICK_DEADZONE, JOYSTICK_X_INVERT), new OH::JoystickAxisSensor(PIN_JOYSTICK_Y, JOYSTICK_DEADZONE, JOYSTICK_Y_INVERT), @@ -67,7 +67,13 @@ OH::JoystickAxisSensor* joystick[] = { }; void setupMode() { + for (int i = 0; i < FINGER_COUNT; i++) { + fingers[i]->setup(); + } + for (int i = 0; i < JOYSTICK_COUNT; i++) { + joystick[i]->setup(); + } } void loopMode() { diff --git a/lib/arduino/sensor/joystick.hpp b/lib/arduino/sensor/joystick.hpp index bcc2b271..0d94ea5a 100644 --- a/lib/arduino/sensor/joystick.hpp +++ b/lib/arduino/sensor/joystick.hpp @@ -33,5 +33,9 @@ namespace OH { public: JoystickAxisSensor(uint8_t pin, float dead_zone, bool invert = false) : pin(pin), dead_zone(dead_zone), invert(invert) {} + + void setup(void) { + pinMode(this->pin, INPUT); + }; }; }; // namespace OH diff --git a/lib/opengloves/sensor/og_finger.hpp b/lib/opengloves/sensor/og_finger.hpp index e1eca696..4a09e0e5 100644 --- a/lib/opengloves/sensor/og_finger.hpp +++ b/lib/opengloves/sensor/og_finger.hpp @@ -34,6 +34,10 @@ namespace OpenGloves FingerSensor(uint8_t pin, bool invert, OH::Calibrator* calibrator) : OH::CalibratedSensor(calibrator), pin(pin), invert(invert) {}; + + void setup(void) { + pinMode(this->pin, INPUT); + }; }; // TODO: add splay finger sensor From 4c292505767032b201fb4cd6eced0430684892f9 Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Fri, 9 Jun 2023 10:34:13 +0400 Subject: [PATCH 03/16] refactor(OpenGloves): use decorator sensors --- .../mode_configs/opengloves/opengloves.cpp | 24 ++++++++---- lib/arduino/sensor/analog.hpp | 37 +++++++++++++++++++ lib/arduino/sensor/joystick.hpp | 31 +++++++--------- lib/opengloves/sensor/og_finger.hpp | 32 ++++------------ lib/opengloves_utils/opengloves_protocol.hpp | 24 ++++++++++++ lib/sensor/sensor.hpp | 4 +- 6 files changed, 100 insertions(+), 52 deletions(-) create mode 100644 lib/arduino/sensor/analog.hpp create mode 100644 lib/opengloves_utils/opengloves_protocol.hpp diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp index 359c78e6..9ca4d895 100644 --- a/firmware/mode_configs/opengloves/opengloves.cpp +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include #include @@ -20,23 +22,23 @@ using namespace OpenGloves; #pragma region FingerSensor #if FINGER_THUMB_ENABLED - auto* fingerThumb = new FingerSensor(PIN_FINGER_THUMB, FINGER_THUMB_INVERT, new CALIBRATION_CURL()); + auto* fingerThumb = new FingerSensor(new OH::AnalogSensor(PIN_FINGER_THUMB), new CALIBRATION_CURL(), EncodedInput::Type::THUMB); #endif #if FINGER_INDEX_ENABLED - auto* fingerIndex = new FingerSensor(PIN_FINGER_INDEX, FINGER_INDEX_INVERT, new CALIBRATION_CURL()); + auto* fingerIndex = new FingerSensor(new OH::AnalogSensor(PIN_FINGER_INDEX), new CALIBRATION_CURL(), EncodedInput::Type::INDEX); #endif #if FINGER_MIDDLE_ENABLED - auto* fingerMiddle = new FingerSensor(PIN_FINGER_MIDDLE, FINGER_MIDDLE_INVERT, new CALIBRATION_CURL()); + auto* fingerMiddle = new FingerSensor(new OH::AnalogSensor(PIN_FINGER_MIDDLE), new CALIBRATION_CURL(), EncodedInput::Type::MIDDLE); #endif #if FINGER_RING_ENABLED - auto* fingerRing = new FingerSensor(PIN_FINGER_RING, FINGER_RING_INVERT, new CALIBRATION_CURL()); + auto* fingerRing = new FingerSensor(new OH::AnalogSensor(PIN_FINGER_RING), new CALIBRATION_CURL(), EncodedInput::Type::RING); #endif #if FINGER_PINKY_ENABLED - auto* fingerPinky = new FingerSensor(PIN_FINGER_PINKY, FINGER_PINKY_INVERT, new CALIBRATION_CURL()); + auto* fingerPinky = new FingerSensor(new OH::AnalogSensor(PIN_FINGER_PINKY), new CALIBRATION_CURL(), EncodedInput::Type::PINKY); #endif FingerSensor* fingers[FINGER_COUNT] = { @@ -59,10 +61,10 @@ FingerSensor* fingers[FINGER_COUNT] = { #pragma endregion -OH::JoystickAxisSensor* joystick[JOYSTICK_COUNT] = { +OH::MemoizedSensor* joystick[JOYSTICK_COUNT] = { #if JOYSTICK_ENABLED - new OH::JoystickAxisSensor(PIN_JOYSTICK_X, JOYSTICK_DEADZONE, JOYSTICK_X_INVERT), - new OH::JoystickAxisSensor(PIN_JOYSTICK_Y, JOYSTICK_DEADZONE, JOYSTICK_Y_INVERT), + new OH::MemoizedSensor(new OH::JoystickAxisSensor(new OH::AnalogSensor(PIN_JOYSTICK_X), JOYSTICK_DEADZONE)), + new OH::MemoizedSensor(new OH::JoystickAxisSensor(new OH::AnalogSensor(PIN_JOYSTICK_Y), JOYSTICK_DEADZONE)), #endif }; @@ -77,5 +79,11 @@ void setupMode() { } void loopMode() { + for (int i = 0; i < FINGER_COUNT; i++) { + // fingers[i]->readValue(); + } + for (int i = 0; i < JOYSTICK_COUNT; i++) { + joystick[i]->updateValue(); + } } diff --git a/lib/arduino/sensor/analog.hpp b/lib/arduino/sensor/analog.hpp new file mode 100644 index 00000000..7d7fa6d9 --- /dev/null +++ b/lib/arduino/sensor/analog.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include + +namespace OH +{ + template + class AnalogSensor : public ISensor + { + private: + uint8_t pin; + + public: + AnalogSensor(uint8_t pin) : pin(pin) {} + + void setup(void) + { + pinMode(this->pin, INPUT); + }; + + uint16_t getValue(void) override; + }; + + template <> + uint16_t AnalogSensor::getValue(void) + { + return analogRead(this->pin); + } + + template <> + uint16_t AnalogSensor::getValue(void) + { + return ANALOG_MAX - analogRead(this->pin); + } +} // namespace OH diff --git a/lib/arduino/sensor/joystick.hpp b/lib/arduino/sensor/joystick.hpp index 0d94ea5a..32c28d30 100644 --- a/lib/arduino/sensor/joystick.hpp +++ b/lib/arduino/sensor/joystick.hpp @@ -5,11 +5,14 @@ #include namespace OH { - class JoystickAxisSensor : public ISensor { + /** + * Joystick axis sensor decorator + */ + template + class JoystickAxisSensor : public ISensor<_Tp> { private: - uint8_t pin; + ISensor<_Tp>* sensor; float dead_zone; - bool invert; int filterDeadZone(int in) { // This function clamps the input to the center of the range if @@ -19,23 +22,17 @@ namespace OH { return abs(center - in) < dead_zone * ANALOG_MAX ? center : in; } - protected: - uint16_t getValue(void) override { - auto value = analogRead(this->pin); - value = this->filterDeadZone(value); - - if (this->invert) { - value = ANALOG_MAX - value; - } - - return value; - } - public: - JoystickAxisSensor(uint8_t pin, float dead_zone, bool invert = false) : pin(pin), dead_zone(dead_zone), invert(invert) {} + JoystickAxisSensor(ISensor<_Tp>* sensor, float dead_zone) : sensor(sensor), dead_zone(dead_zone) {}; void setup(void) { - pinMode(this->pin, INPUT); + this->sensor->setup(); }; + + uint16_t getValue(void) override { + auto value = this->sensor->getValue(); + value = this->filterDeadZone(value); + return value; + } }; }; // namespace OH diff --git a/lib/opengloves/sensor/og_finger.hpp b/lib/opengloves/sensor/og_finger.hpp index 4a09e0e5..2f7c7385 100644 --- a/lib/opengloves/sensor/og_finger.hpp +++ b/lib/opengloves/sensor/og_finger.hpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -11,33 +12,14 @@ namespace OpenGloves // }; - class FingerSensor : public IFinger, public OH::CalibratedSensor + class FingerSensor : public IFinger, public OH::CalibratedSensor, public EncodedInput { - private: - uint8_t pin; - bool invert; + private: + EncodedInput::Type type; - protected: - uint16_t updateValue(void) override { - auto value = analogRead(this->pin); - - if (this->invert) { - value = ANALOG_MAX - value; - } - - // TODO: add median filter - - return value; - }; - - public: - FingerSensor(uint8_t pin, bool invert, OH::Calibrator* calibrator) : - OH::CalibratedSensor(calibrator), - pin(pin), invert(invert) {}; - - void setup(void) { - pinMode(this->pin, INPUT); - }; + public: + FingerSensor(ISensor* sensor, OH::Calibrator* calibrator, EncodedInput::Type type) + : CalibratedSensor(sensor, calibrator), type(type) {} }; // TODO: add splay finger sensor diff --git a/lib/opengloves_utils/opengloves_protocol.hpp b/lib/opengloves_utils/opengloves_protocol.hpp new file mode 100644 index 00000000..ead46e27 --- /dev/null +++ b/lib/opengloves_utils/opengloves_protocol.hpp @@ -0,0 +1,24 @@ +#pragma once + +namespace OpenGloves +{ + struct EncodedInput { + enum Type : char { + THUMB = 'A', + INDEX = 'B', + MIDDLE = 'C', + RING = 'D', + PINKY = 'E', + JOY_X = 'F', + JOY_Y = 'G', + JOY_BTN = 'H', + TRIGGER = 'I', + A_BTN = 'J', + B_BTN = 'K', + GRAB = 'L', + PINCH = 'M', + MENU = 'N', + CALIBRATE = 'O' + }; + }; +} // namespace OpenGloves diff --git a/lib/sensor/sensor.hpp b/lib/sensor/sensor.hpp index a1ce2043..d0e8af2c 100644 --- a/lib/sensor/sensor.hpp +++ b/lib/sensor/sensor.hpp @@ -102,7 +102,7 @@ namespace OH }; void resetCalibration() override { - calibrator->reset(); - } + this->calibrator->reset(); + }; }; } // namespace OH From 4be4071dcd543366ac14df6bd361e0a7c75370ae Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Fri, 9 Jun 2023 21:31:32 +0400 Subject: [PATCH 04/16] feat(OpenGloves): ouput fingers --- .../mode_configs/opengloves/opengloves.cpp | 73 +++++++++++++++---- lib/calibration/calibration.hpp | 14 ++-- lib/core/utility.hpp | 1 + lib/opengloves/sensor/og_finger.hpp | 49 +++++++++---- lib/opengloves/sensor/og_joystick.hpp | 8 ++ lib/opengloves/sensor/og_sensor.hpp | 23 ++++++ lib/opengloves_utils/opengloves_protocol.hpp | 47 +++++++----- lib/sensor/sensor.hpp | 25 +++++-- 8 files changed, 180 insertions(+), 60 deletions(-) create mode 100644 lib/opengloves/sensor/og_joystick.hpp create mode 100644 lib/opengloves/sensor/og_sensor.hpp diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp index 9ca4d895..d74af2d2 100644 --- a/firmware/mode_configs/opengloves/opengloves.cpp +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -3,6 +3,7 @@ #include #include #include + #include #define CALIBRATION_CURL OH::MinMaxCalibrator @@ -14,31 +15,37 @@ #define FINGER_PINKY_ENABLED (PIN_FINGER_PINKY != -1) #define FINGER_COUNT (FINGER_THUMB_ENABLED + FINGER_INDEX_ENABLED + FINGER_MIDDLE_ENABLED + FINGER_RING_ENABLED + FINGER_PINKY_ENABLED) +#define FINGER_CLASS(type, pin, invert, calib) new FingerSensor(new OH::CalibratedSensor(new OH::AnalogSensor(pin), new calib()), type) + #define JOYSTICK_ENABLED (PIN_JOYSTICK_X != -1 && PIN_JOYSTICK_Y != -1) #define JOYSTICK_COUNT (JOYSTICK_ENABLED ? 2 : 0) +#define JOYSTICK_CLASS(type, pin, invert, deadzone) new OH::MemoizedSensor(new OH::JoystickAxisSensor(new OH::AnalogSensor(pin), deadzone)) + +#define INPUTS_COUNT (FINGER_COUNT) + using namespace OpenGloves; #pragma region FingerSensor #if FINGER_THUMB_ENABLED - auto* fingerThumb = new FingerSensor(new OH::AnalogSensor(PIN_FINGER_THUMB), new CALIBRATION_CURL(), EncodedInput::Type::THUMB); + auto* fingerThumb = FINGER_CLASS(EncodedInput::Type::THUMB, PIN_FINGER_THUMB, FINGER_THUMB_INVERT, CALIBRATION_CURL); #endif #if FINGER_INDEX_ENABLED - auto* fingerIndex = new FingerSensor(new OH::AnalogSensor(PIN_FINGER_INDEX), new CALIBRATION_CURL(), EncodedInput::Type::INDEX); + auto* fingerIndex = FINGER_CLASS(EncodedInput::Type::INDEX, PIN_FINGER_INDEX, FINGER_INDEX_INVERT, CALIBRATION_CURL); #endif #if FINGER_MIDDLE_ENABLED - auto* fingerMiddle = new FingerSensor(new OH::AnalogSensor(PIN_FINGER_MIDDLE), new CALIBRATION_CURL(), EncodedInput::Type::MIDDLE); + auto* fingerMiddle = FINGER_CLASS(EncodedInput::Type::MIDDLE, PIN_FINGER_MIDDLE, FINGER_MIDDLE_INVERT, CALIBRATION_CURL); #endif #if FINGER_RING_ENABLED - auto* fingerRing = new FingerSensor(new OH::AnalogSensor(PIN_FINGER_RING), new CALIBRATION_CURL(), EncodedInput::Type::RING); + auto* fingerRing = FINGER_CLASS(EncodedInput::Type::RING, PIN_FINGER_RING, FINGER_RING_INVERT, CALIBRATION_CURL); #endif #if FINGER_PINKY_ENABLED - auto* fingerPinky = new FingerSensor(new OH::AnalogSensor(PIN_FINGER_PINKY), new CALIBRATION_CURL(), EncodedInput::Type::PINKY); + auto* fingerPinky = FINGER_CLASS(EncodedInput::Type::PINKY, PIN_FINGER_PINKY, FINGER_PINKY_INVERT, CALIBRATION_CURL); #endif FingerSensor* fingers[FINGER_COUNT] = { @@ -63,27 +70,63 @@ FingerSensor* fingers[FINGER_COUNT] = { OH::MemoizedSensor* joystick[JOYSTICK_COUNT] = { #if JOYSTICK_ENABLED - new OH::MemoizedSensor(new OH::JoystickAxisSensor(new OH::AnalogSensor(PIN_JOYSTICK_X), JOYSTICK_DEADZONE)), - new OH::MemoizedSensor(new OH::JoystickAxisSensor(new OH::AnalogSensor(PIN_JOYSTICK_Y), JOYSTICK_DEADZONE)), + JOYSTICK_CLASS(EncodedInput::Type::JOY_X, PIN_JOYSTICK_X, JOYSTICK_X_INVERT, JOYSTICK_DEADZONE), + JOYSTICK_CLASS(EncodedInput::Type::JOY_Y, PIN_JOYSTICK_Y, JOYSTICK_Y_INVERT, JOYSTICK_DEADZONE), #endif }; +IEncodedSensor* inputs[INPUTS_COUNT]; +char* encoded_output_string; + void setupMode() { - for (int i = 0; i < FINGER_COUNT; i++) { - fingers[i]->setup(); + size_t currentSensor = 0; + + for (size_t i = 0; i < FINGER_COUNT; i++) { + auto* finger = fingers[i]; + inputs[currentSensor++] = finger; + finger->setup(); + finger->enableCalibration(); } - for (int i = 0; i < JOYSTICK_COUNT; i++) { + for (size_t i = 0; i < JOYSTICK_COUNT; i++) { + // sensors[currentSensor++] = joystick[i]; joystick[i]->setup(); } + + int string_size = 0; + for(size_t i = 0; i < INPUTS_COUNT; i++) { + string_size += inputs[i]->getEncodedSize(); + } + + // Add 1 for new line and 1 for the null terminator. + encoded_output_string = new char[string_size + 1 + 1]; + + Serial.begin(115200); } -void loopMode() { - for (int i = 0; i < FINGER_COUNT; i++) { - // fingers[i]->readValue(); +int encodeAll(char* output, IEncodedSensor* encoders[], size_t count) { + int offset = 0; + // Loop over all of the encoders and encode them to the output string. + for (size_t i = 0; i < count; i++) { + // The offset is the total charecters already added to the string. + offset += encoders[i]->encode(output+offset); } - for (int i = 0; i < JOYSTICK_COUNT; i++) { - joystick[i]->updateValue(); + // Add a new line to the end of the encoded string. + output[offset++] = '\n'; + output[offset] = '\0'; + + return offset; +} + +void loopMode() { + // update all sensor values + for (int i = 0; i < INPUTS_COUNT; i++) { + auto* sensor = inputs[i]; + sensor->updateValue(); } + + // encode all sensor values + encodeAll(encoded_output_string, inputs, INPUTS_COUNT); + Serial.print(encoded_output_string); } diff --git a/lib/calibration/calibration.hpp b/lib/calibration/calibration.hpp index a4f9894e..2012c7b8 100644 --- a/lib/calibration/calibration.hpp +++ b/lib/calibration/calibration.hpp @@ -9,19 +9,19 @@ namespace OH { class Calibrated { + protected: + bool calibrate = false; + public: virtual void resetCalibration() = 0; - virtual void enableCalibration() { + void enableCalibration() { calibrate = true; } - virtual void disableCalibration() { + void disableCalibration() { calibrate = false; } - - protected: - bool calibrate; }; template @@ -54,11 +54,11 @@ namespace OH { return (output_min + output_max) / 2.0f; } - if (input < value_min) { + if (input <= value_min) { return output_min; } - if (input > value_max) { + if (input >= value_max) { return output_max; } diff --git a/lib/core/utility.hpp b/lib/core/utility.hpp index 7533b8e1..f793c0f9 100644 --- a/lib/core/utility.hpp +++ b/lib/core/utility.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/lib/opengloves/sensor/og_finger.hpp b/lib/opengloves/sensor/og_finger.hpp index 2f7c7385..a5c02521 100644 --- a/lib/opengloves/sensor/og_finger.hpp +++ b/lib/opengloves/sensor/og_finger.hpp @@ -1,25 +1,48 @@ #pragma once -#include -#include -#include - -#include +#include "og_sensor.hpp" namespace OpenGloves { - struct IFinger { - // + class IFinger : public ICalibratedEncodedSensor, public OH::MemoizedSensor { + public : + IFinger(OH::CalibratedSensor* sensor, EncodedInput::Type type) + : ICalibratedEncodedSensor(type), OH::MemoizedSensor(sensor) { }; }; - class FingerSensor : public IFinger, public OH::CalibratedSensor, public EncodedInput + class FingerSensor : public IFinger { - private: - EncodedInput::Type type; - public: - FingerSensor(ISensor* sensor, OH::Calibrator* calibrator, EncodedInput::Type type) - : CalibratedSensor(sensor, calibrator), type(type) {} + FingerSensor(OH::CalibratedSensor* sensor, EncodedInput::Type type) : IFinger(sensor, type) { }; + + void setup() override { + this->sensor->setup(); + } + + void updateValue() override { + this->value = this->sensor->getValue(); + } + + void resetCalibration() override { + static_cast*>(this->sensor)->resetCalibration(); + } + + void enableCalibration() override { + static_cast*>(this->sensor)->enableCalibration(); + } + + void disableCalibration() override { + static_cast*>(this->sensor)->disableCalibration(); + } + + size_t getEncodedSize() const override { + // Encode string size = AXXXX + '\0' + return 6; + } + + int encode(char* buffer) const override { + return snprintf(buffer, this->getEncodedSize(), "%c%04d", this->getType(), this->value); + } }; // TODO: add splay finger sensor diff --git a/lib/opengloves/sensor/og_joystick.hpp b/lib/opengloves/sensor/og_joystick.hpp new file mode 100644 index 00000000..3d6f63c2 --- /dev/null +++ b/lib/opengloves/sensor/og_joystick.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "og_sensor.hpp" + +namespace OpenGloves +{ + // typedef SingleAnalogValueEncodedSensor EncidedJoystickSensor; +} // namespace OpenGloves diff --git a/lib/opengloves/sensor/og_sensor.hpp b/lib/opengloves/sensor/og_sensor.hpp new file mode 100644 index 00000000..35e890a6 --- /dev/null +++ b/lib/opengloves/sensor/og_sensor.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +namespace OpenGloves +{ + class IEncodedSensor : public EncodedInput { + public: + IEncodedSensor(Type type) : EncodedInput(type) { }; + virtual void setup() = 0; + virtual void updateValue() = 0; + }; + + struct ICalibratedEncodedSensor : public IEncodedSensor { + public: + ICalibratedEncodedSensor(Type type) : IEncodedSensor(type) { }; + virtual void resetCalibration() = 0; + virtual void enableCalibration() = 0; + virtual void disableCalibration() = 0; + }; +} // namespace OpenGloves diff --git a/lib/opengloves_utils/opengloves_protocol.hpp b/lib/opengloves_utils/opengloves_protocol.hpp index ead46e27..417c20bf 100644 --- a/lib/opengloves_utils/opengloves_protocol.hpp +++ b/lib/opengloves_utils/opengloves_protocol.hpp @@ -3,22 +3,35 @@ namespace OpenGloves { struct EncodedInput { - enum Type : char { - THUMB = 'A', - INDEX = 'B', - MIDDLE = 'C', - RING = 'D', - PINKY = 'E', - JOY_X = 'F', - JOY_Y = 'G', - JOY_BTN = 'H', - TRIGGER = 'I', - A_BTN = 'J', - B_BTN = 'K', - GRAB = 'L', - PINCH = 'M', - MENU = 'N', - CALIBRATE = 'O' - }; + public: + enum Type : char { + THUMB = 'A', + INDEX = 'B', + MIDDLE = 'C', + RING = 'D', + PINKY = 'E', + JOY_X = 'F', + JOY_Y = 'G', + JOY_BTN = 'H', + TRIGGER = 'I', + A_BTN = 'J', + B_BTN = 'K', + GRAB = 'L', + PINCH = 'M', + MENU = 'N', + CALIBRATE = 'O' + }; + + EncodedInput(Type type) : type(type) { }; + + constexpr Type getType() const { + return this->type; + } + + virtual size_t getEncodedSize() const = 0; + virtual int encode(char* buffer) const = 0; + + private: + Type type; }; } // namespace OpenGloves diff --git a/lib/sensor/sensor.hpp b/lib/sensor/sensor.hpp index d0e8af2c..7c27608b 100644 --- a/lib/sensor/sensor.hpp +++ b/lib/sensor/sensor.hpp @@ -2,6 +2,7 @@ #include +#include #include #if defined(__AVR__) @@ -27,7 +28,7 @@ namespace OH /** * Setup the sensor hardware */ - virtual void setup() {}; + virtual void setup() = 0; /** * Get the current sensor value @@ -84,6 +85,16 @@ namespace OH ISensor<_Tp>* sensor; Calibrator<_Tp>* calibrator; + _Tp getCalibratedValue() { + auto value = this->sensor->getValue(); + + if (this->calibrate) { + this->calibrator->update(value); + } + + return this->calibrator->calibrate(value); + } + public: /** * @param sensor Sensor to be decorated @@ -91,14 +102,12 @@ namespace OH */ CalibratedSensor(ISensor<_Tp>* sensor, Calibrator<_Tp>* calibrator) : sensor(sensor), calibrator(calibrator) {}; - _Tp getValue() override { - auto value = this->sensor->getValue(); - - if (this->calibrate) { - this->calibrator->update(value); - } + void setup() override { + this->sensor->setup(); + }; - return this->calibrator->calibrate(value); + _Tp getValue() override { + return this->getCalibratedValue(); }; void resetCalibration() override { From 19a1027af63e03fb798ff57ce5e60ceee6a3fbee Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Fri, 9 Jun 2023 22:18:33 +0400 Subject: [PATCH 05/16] ci(GitHub): job for OpenGloves --- .github/workflows/ci.yml | 117 ++++++++++++++++-- .../mode_configs/opengloves/opengloves.cpp | 2 + lib/calibration/calibration.hpp | 56 ++++----- 3 files changed, 140 insertions(+), 35 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ec8db0f..a50a53a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,10 +58,6 @@ jobs: serial_plotter_flag: SERIAL_PLOTTER=false nimble_flag: BLUETOOTH_USE_NIMBLE=true - - target: opengloves - os: ubuntu-latest - coverage: true - steps: - uses: actions/checkout@v3 @@ -84,7 +80,9 @@ jobs: - name: Cache PlatformIO uses: actions/cache@v3 with: - path: ~/.platformio + path: | + ~/.platformio/.cache + ./.pio key: ${{ runner.os }}-pio-${{ matrix.target }}-${{ hashFiles('platformio.ini') }} restore-keys: | ${{ runner.os }}-pio-${{ matrix.target }}- @@ -153,6 +151,109 @@ jobs: path: ./build/lcov/lcov.info.${{matrix.target}} retention-days: 5 + build-opengloves: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest ] + target: + - opengloves + curl_calibration_flag: + - CALIBRATION_CURL="OH::MinMaxCalibrator" + - CALIBRATION_CURL="OH::CenterPointDeviationCalibrator" + - CALIBRATION_CURL="OH::FixedCenterPointDeviationCalibrator" + coverage: [ true ] + + steps: + - uses: actions/checkout@v3 + + - name: Speedup package installation + if: matrix.coverage + uses: abbbi/github-actions-tune@v1 + + - name: Setup LCOV + if: matrix.coverage + uses: hrishikesh-kadam/setup-lcov@v1 + + - name: Cache pip + uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Cache PlatformIO + uses: actions/cache@v3 + with: + path: | + ~/.platformio/.cache + ./.pio + key: ${{ runner.os }}-pio-${{ matrix.target }}-${{ hashFiles('platformio.ini') }} + restore-keys: | + ${{ runner.os }}-pio-${{ matrix.target }}- + ${{ runner.os }}-pio- + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.9' + + - name: Enable coverage (non-macOS) + if: runner.os != 'macOS' && matrix.coverage + run: | + sed -i '/__OH_FIRMWARE__/p; s/-D __OH_FIRMWARE__/-lgcov --coverage/' platformio.ini + - name: Enable coverage (macOS) + if: runner.os == 'macOS' && matrix.coverage + run: | + sed -i '' '/__OH_FIRMWARE__/p; s/-D __OH_FIRMWARE__/-lgcov --coverage/' platformio.ini + + - name: Update build flags (non-macOS) + if: runner.os != 'macOS' + run: | + sed -i '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.curl_calibration_flag }}/' platformio.ini + - name: Update build flags (macOS) + if: runner.os == 'macOS' + run: | + sed -i '' '/__OH_FIRMWARE__/p; s/__OH_FIRMWARE__/${{ matrix.curl_calibration_flag }}/' platformio.ini + + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + pio upgrade --dev + pio pkg update --global + + - name: Install libs + run: pio pkg install -e ${{matrix.target}} + + - name: Change memory segments + if: matrix.coverage + run: | + sed -i "s/len\s=\s0x2c200\s-\s0xdb5c/len = 289888/" ~/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/ld/memory.ld + + - name: Build + run: | + echo "::group::platformio.ini" + cat platformio.ini + echo "::endgroup::" + pio run --environment ${{matrix.target}} + + - name: Collect initial coverage + if: matrix.coverage + run: | + mkdir -p ./build/lcov + lcov -i -d ./.pio/build/${{matrix.target}}/ -c -o ./build/lcov/lcov.info.${{matrix.target}}-${{ hashFiles('platformio.ini') }} -gcov-tool ~/.platformio/packages/toolchain-xtensa-esp32/bin/xtensa-esp32-elf-gcov + + - name: Upload coverage Artifact + uses: actions/upload-artifact@v3 + if: matrix.coverage + with: + name: lcov.info.${{matrix.target}}-${{ hashFiles('platformio.ini') }} + path: ./build/lcov/lcov.info.${{matrix.target}}-* + retention-days: 5 + test: runs-on: ubuntu-latest strategy: @@ -181,7 +282,9 @@ jobs: - name: Cache PlatformIO uses: actions/cache@v3 with: - path: ~/.platformio + path: | + ~/.platformio/.cache + ./.pio key: ${{ runner.os }}-pio-${{ matrix.target }}-${{ hashFiles('platformio.ini') }} restore-keys: | ${{ runner.os }}-pio-${{ matrix.target }} @@ -220,7 +323,7 @@ jobs: coverage-report: needs: - build-bhaptics - # - build-opengloves + - build-opengloves - test runs-on: ubuntu-latest steps: diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp index d74af2d2..d52f726a 100644 --- a/firmware/mode_configs/opengloves/opengloves.cpp +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -6,7 +6,9 @@ #include +#ifndef CALIBRATION_CURL #define CALIBRATION_CURL OH::MinMaxCalibrator +#endif #define FINGER_THUMB_ENABLED (PIN_FINGER_THUMB != -1) #define FINGER_INDEX_ENABLED (PIN_FINGER_INDEX != -1) diff --git a/lib/calibration/calibration.hpp b/lib/calibration/calibration.hpp index 2012c7b8..d7cc1186 100644 --- a/lib/calibration/calibration.hpp +++ b/lib/calibration/calibration.hpp @@ -24,15 +24,15 @@ namespace OH { } }; - template + template struct Calibrator { virtual void reset() = 0; - virtual void update(T input) = 0; - virtual T calibrate(T input) const = 0; + virtual void update(_Tp input) = 0; + virtual _Tp calibrate(_Tp input) const = 0; }; - template - class MinMaxCalibrator : public Calibrator { + template + class MinMaxCalibrator : public Calibrator<_Tp> { public: MinMaxCalibrator() : value_min(output_max), value_max(output_min) {} @@ -41,13 +41,13 @@ namespace OH { value_max = output_min; } - void update(T input) { + void update(_Tp input) { // Update the min and the max. if (input < value_min) value_min = input; if (input > value_max) value_max = input; } - T calibrate(T input) const { + _Tp calibrate(_Tp input) const { // This means we haven't had any calibration data yet. // Return a neutral value right in the middle of the output range. if (value_min > value_max) { @@ -63,19 +63,19 @@ namespace OH { } // Map the input range to the output range. - T output = accurateMap(input, value_min, value_max, output_min, output_max); + _Tp output = accurateMap<_Tp>(input, value_min, value_max, output_min, output_max); // Lock the range to the output. return constrain(output, output_min, output_max); } private: - T value_min; - T value_max; + _Tp value_min; + _Tp value_max; }; - template - class CenterPointDeviationCalibrator : public Calibrator { + template + class CenterPointDeviationCalibrator : public Calibrator<_Tp> { public: CenterPointDeviationCalibrator() : range_min(sensor_max), range_max(0) {} @@ -84,49 +84,49 @@ namespace OH { range_max = 0; } - void update(T input) { + void update(_Tp input) { // Update the min and the max. - if (input < range_min) range_min = accurateMap(input, output_min, output_max, 0, sensor_max); - if (input > range_max) range_max = accurateMap(input, output_min, output_max, 0, sensor_max); + if (input < range_min) range_min = accurateMap<_Tp>(input, output_min, output_max, 0, sensor_max); + if (input > range_max) range_max = accurateMap<_Tp>(input, output_min, output_max, 0, sensor_max); } - T calibrate(T input) const { + _Tp calibrate(_Tp input) const { // Find the center point of the sensor so we know how much we have deviated from it. - T center = (range_min + range_max) / 2.0f; + _Tp center = (range_min + range_max) / 2.0f; // Map the input to the sensor range of motion. - T output = accurateMap(input, output_min, output_max, 0, sensor_max); + _Tp output = accurateMap<_Tp>(input, output_min, output_max, 0, sensor_max); // Find the deviation from the center and constrain it to the maximum that the driver supports. output = constrain(output - center, -driver_max_deviation, driver_max_deviation); // Finally map the deviation from the center back to the output range. - return accurateMap(output, -driver_max_deviation, driver_max_deviation, output_min, output_max); + return accurateMap(output, -driver_max_deviation, driver_max_deviation, output_min, output_max); } private: - T range_min; - T range_max; + _Tp range_min; + _Tp range_max; }; - template - class FixedCenterPointDeviationCalibrator : public Calibrator { + template + class FixedCenterPointDeviationCalibrator : public Calibrator<_Tp> { public: void reset() {} - void update(T input) {} + void update(_Tp input) {} - T calibrate(T input) const { + _Tp calibrate(_Tp input) const { // Find the center point of the sensor so we know how much we have deviated from it. - T center = sensor_max / 2.0f; + _Tp center = sensor_max / 2.0f; // Map the input to the sensor range of motion. - T output = accurateMap(input, output_min, output_max, 0, sensor_max); + _Tp output = accurateMap<_Tp>(input, output_min, output_max, 0, sensor_max); // Find the deviation from the center and constrain it to the maximum that the driver supports. output = constrain(output - center, -driver_max_deviation, driver_max_deviation); // Finally map the deviation from the center back to the output range. - return accurateMap(output, -driver_max_deviation, driver_max_deviation, output_min, output_max); + return (_Tp) accurateMap(output, -driver_max_deviation, driver_max_deviation, output_min, output_max); } }; } From f6c4cf2f94ffd6b48bf57abf9bee7f05fd4825fa Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Sat, 10 Jun 2023 01:12:43 +0400 Subject: [PATCH 06/16] test(Calibration): cover FixedCenterPointDeviation --- lib/calibration/calibration.hpp | 10 ++++--- lib/core/utility.hpp | 11 +++++-- test/test_calibration/main.cpp | 51 +++++++++++++++++++++++++++++++++ test/test_core_utility/main.cpp | 2 ++ 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/lib/calibration/calibration.hpp b/lib/calibration/calibration.hpp index d7cc1186..09297028 100644 --- a/lib/calibration/calibration.hpp +++ b/lib/calibration/calibration.hpp @@ -77,7 +77,9 @@ namespace OH { template class CenterPointDeviationCalibrator : public Calibrator<_Tp> { public: - CenterPointDeviationCalibrator() : range_min(sensor_max), range_max(0) {} + CenterPointDeviationCalibrator() : range_min(sensor_max), range_max(0) { + #warning "CenterPointDeviationCalibrator is untested and may not work as expected." + } void reset() { range_min = sensor_max; @@ -95,13 +97,13 @@ namespace OH { _Tp center = (range_min + range_max) / 2.0f; // Map the input to the sensor range of motion. - _Tp output = accurateMap<_Tp>(input, output_min, output_max, 0, sensor_max); + int output = accurateMap<_Tp>(input, output_min, output_max, 0, sensor_max); // Find the deviation from the center and constrain it to the maximum that the driver supports. output = constrain(output - center, -driver_max_deviation, driver_max_deviation); // Finally map the deviation from the center back to the output range. - return accurateMap(output, -driver_max_deviation, driver_max_deviation, output_min, output_max); + return (_Tp) accurateMap(output, -driver_max_deviation, driver_max_deviation, output_min, output_max); } private: @@ -120,7 +122,7 @@ namespace OH { _Tp center = sensor_max / 2.0f; // Map the input to the sensor range of motion. - _Tp output = accurateMap<_Tp>(input, output_min, output_max, 0, sensor_max); + int output = accurateMap<_Tp>(input, output_min, output_max, 0, sensor_max); // Find the deviation from the center and constrain it to the maximum that the driver supports. output = constrain(output - center, -driver_max_deviation, driver_max_deviation); diff --git a/lib/core/utility.hpp b/lib/core/utility.hpp index f793c0f9..d80469c8 100644 --- a/lib/core/utility.hpp +++ b/lib/core/utility.hpp @@ -31,8 +31,15 @@ namespace OH { }; template - constexpr inline _Tp accurateMap(_Tp x, _Tp in_min, _Tp in_max, _Tp out_min, _Tp out_max) { - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; + constexpr _Tp accurateMap(_Tp x, _Tp in_min, _Tp in_max, _Tp out_min, _Tp out_max) { + const _Tp run = in_max - in_min; + if(run == 0){ + log_e("map(): Invalid input range, min == max"); + return (out_min + out_max) / 2; + } + const _Tp rise = out_max - out_min; + const _Tp delta = x - in_min; + return (delta * rise) / run + out_min; } // Same as the above, but both mins are 0. diff --git a/test/test_calibration/main.cpp b/test/test_calibration/main.cpp index 5d97d41f..fffcde13 100644 --- a/test/test_calibration/main.cpp +++ b/test/test_calibration/main.cpp @@ -34,10 +34,61 @@ void test_minmax_calibrator(void) { TEST_ASSERT_EQUAL_UINT16(2048, calibrator->calibrate(4096)); } +void test_fixed_center_point_deviation_calibrator(void) { + auto calibrator = new FixedCenterPointDeviationCalibrator(); + + // below deviation + TEST_ASSERT_EQUAL_UINT16(0, calibrator->calibrate(0)); + TEST_ASSERT_EQUAL_UINT16(0, calibrator->calibrate(10)); + TEST_ASSERT_EQUAL_UINT16(0, calibrator->calibrate(1234)); + TEST_ASSERT_EQUAL_UINT16(0, calibrator->calibrate(1536)); + // center point + TEST_ASSERT_EQUAL_UINT16(32, calibrator->calibrate(1544)); + TEST_ASSERT_EQUAL_UINT16(32, calibrator->calibrate(1550)); + TEST_ASSERT_EQUAL_UINT16(64, calibrator->calibrate(1555)); + TEST_ASSERT_EQUAL_UINT16(96, calibrator->calibrate(1560)); + TEST_ASSERT_EQUAL_UINT16(256, calibrator->calibrate(1600)); + TEST_ASSERT_EQUAL_UINT16(1056, calibrator->calibrate(1800)); + TEST_ASSERT_EQUAL_UINT16(1440, calibrator->calibrate(1900)); + TEST_ASSERT_EQUAL_UINT16(2048, calibrator->calibrate(2048)); + TEST_ASSERT_EQUAL_UINT16(2656, calibrator->calibrate(2200)); + TEST_ASSERT_EQUAL_UINT16(3232, calibrator->calibrate(2345)); + // above deviation + TEST_ASSERT_EQUAL_UINT16(4096, calibrator->calibrate(4086)); + TEST_ASSERT_EQUAL_UINT16(4096, calibrator->calibrate(4096)); + + calibrator->reset(); + calibrator->update(1234); + calibrator->update(2345); + + // update does not change the calibration as the deviation is fixed + + // below deviation + TEST_ASSERT_EQUAL_UINT16(0, calibrator->calibrate(0)); + TEST_ASSERT_EQUAL_UINT16(0, calibrator->calibrate(10)); + TEST_ASSERT_EQUAL_UINT16(0, calibrator->calibrate(1234)); + TEST_ASSERT_EQUAL_UINT16(0, calibrator->calibrate(1536)); + // center point + TEST_ASSERT_EQUAL_UINT16(32, calibrator->calibrate(1544)); + TEST_ASSERT_EQUAL_UINT16(32, calibrator->calibrate(1550)); + TEST_ASSERT_EQUAL_UINT16(64, calibrator->calibrate(1555)); + TEST_ASSERT_EQUAL_UINT16(96, calibrator->calibrate(1560)); + TEST_ASSERT_EQUAL_UINT16(256, calibrator->calibrate(1600)); + TEST_ASSERT_EQUAL_UINT16(1056, calibrator->calibrate(1800)); + TEST_ASSERT_EQUAL_UINT16(1440, calibrator->calibrate(1900)); + TEST_ASSERT_EQUAL_UINT16(2048, calibrator->calibrate(2048)); + TEST_ASSERT_EQUAL_UINT16(2656, calibrator->calibrate(2200)); + TEST_ASSERT_EQUAL_UINT16(3232, calibrator->calibrate(2345)); + // above deviation + TEST_ASSERT_EQUAL_UINT16(4096, calibrator->calibrate(4086)); + TEST_ASSERT_EQUAL_UINT16(4096, calibrator->calibrate(4096)); +} + int process(void) { UNITY_BEGIN(); RUN_TEST(test_minmax_calibrator); + RUN_TEST(test_fixed_center_point_deviation_calibrator); return UNITY_END(); } diff --git a/test/test_core_utility/main.cpp b/test/test_core_utility/main.cpp index d8afab4f..4e9c684f 100644 --- a/test/test_core_utility/main.cpp +++ b/test/test_core_utility/main.cpp @@ -54,6 +54,8 @@ void test_accurate_map(void) { TEST_ASSERT_EQUAL_UINT16(0, accurateMap(2048, 2048, 4095, 0, 255)); TEST_ASSERT_EQUAL_UINT16(127, accurateMap(3071, 2048, 4095, 0, 255)); TEST_ASSERT_EQUAL_UINT16(255, accurateMap(4095, 2048, 4095, 0, 255)); + + TEST_ASSERT_EQUAL_UINT16(2047, accurateMap(343, 343, 343, 0, 4095)); } void test_simple_map(void) { From 7d6183871e87f649028251d10f86229b0d54b63f Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Sat, 10 Jun 2023 01:36:29 +0400 Subject: [PATCH 07/16] docs(OpenGloves): add credits --- .vscode/settings.json | 7 ++++++- README.md | 24 +++++++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ae85168d..85901741 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -53,7 +53,12 @@ "bit": "cpp", "set": "cpp", "iostream": "cpp", - "*.hpp": "cpp" + "*.hpp": "cpp", + "xlocmon": "cpp", + "xmemory": "cpp", + "xtree": "cpp", + "xhash": "cpp", + "xlocnum": "cpp" }, "files.eol": "\n", "files.insertFinalNewline": true, diff --git a/README.md b/README.md index 1b440d7e..be158554 100644 --- a/README.md +++ b/README.md @@ -73,21 +73,27 @@ Please note, that documentation is still work-in-progress ## Supported devices -| Device | Supported Devices | Retail price | DIY Price | Hardware | -| :-------------------- | :------------------- | -----------: | --------: | :-------------------------------------------------------------------------------------------------- | -| Haptics Face Interface | Tactal | US $149 | ~20$ | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#haptic-face-interface) | -| Haptic Gloves | TactGlove | US $299 | ~20$ | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#haptic-glove) | -| Haptic Sleeves | Tactosy for arms | US $249 | ~20$ | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#haptic-forearm-sleeve) | -| Haptic Hand Gauntlet | Tactosy for hands | US $249 | ~20$ | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#haptic-gauntlet) | -| Haptic Feet Device | Tactosy for feet | US $249 | ~20$ | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#haptic-feet-device) | -| X16 Haptic Vest | TactSuit X16 | US $299 | ~40$ | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#x16-haptic-vest) | -| X40 Haptic Vest | TactSuit X40, Tactot | US $499 | ~70$ | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#x40-haptic-vest) | +| Device | Supported Devices | Retail price | DIY Price | Hardware | +| :-------------------- | :------------------- | -----------: | ----------------: | :------------------------------------------------------------------------------------------------ | +| Haptics Face Interface | Tactal, TactVisor | US $149 | ~$20 | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#haptic-face-interface) | +| Haptic Gloves | TactGlove | US $299 | ~$20 | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#haptic-glove) | +| Haptic Sleeves | Tactosy for arms | US $249 | ~$20 | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#haptic-forearm-sleeve) | +| Haptic Hand Gauntlet | Tactosy for hands | US $249 | ~$20 | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#haptic-gauntlet) | +| Haptic Feet Device | Tactosy for feet | US $249 | ~$20 | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#haptic-feet-device) | +| X16 Haptic Vest | TactSuit X16 | US $299 | ~$40 | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#x16-haptic-vest) | +| X40 Haptic Vest | TactSuit X40, Tactot | US $499 | ~$70 | See [Hardware Reference](https://github.com/senseshift/senseshift-hardware#x40-haptic-vest) | +| VR Glove / OpenGloves | LucidGloves | N/A | ~$40 — ~$80 | See [Original Wiki](https://github.com/LucidVR/lucidgloves/wiki) | ## For Developers * [Code of Conduct](./CODE_OF_CONDUCT.md) * [Contributing Guidelines](./CONTRIBUTING.md) +## Credits + +* [LucasVRTech](https://github.com/lucas-vrtech) of the LucidGlove project +* [JohnRThomas](https://github.com/JohnRThomas) for the his implementation of LucidGlove firmware + ## Licensing [![GPL-3.0](https://www.gnu.org/graphics/gplv3-or-later-sm.png)](./LICENSE) From 0909a7abc17abb475916798c03bf14f2edbc41d0 Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Sat, 10 Jun 2023 17:22:55 +0400 Subject: [PATCH 08/16] feat(OpenGloves): add serial communication class --- .../mode_configs/opengloves/opengloves.cpp | 64 +++++-------------- .../og_protocol.hpp} | 18 +++++- lib/opengloves/sensor/og_finger.hpp | 4 +- lib/opengloves/sensor/og_sensor.hpp | 9 +-- .../og_serial_commmunications.hpp | 36 +++++++++++ 5 files changed, 72 insertions(+), 59 deletions(-) rename lib/{opengloves_utils/opengloves_protocol.hpp => opengloves/og_protocol.hpp} (60%) create mode 100644 lib/opengloves_serial/og_serial_commmunications.hpp diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp index d52f726a..a8e758bb 100644 --- a/firmware/mode_configs/opengloves/opengloves.cpp +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -3,8 +3,8 @@ #include #include #include - #include +#include #ifndef CALIBRATION_CURL #define CALIBRATION_CURL OH::MinMaxCalibrator @@ -24,30 +24,28 @@ #define JOYSTICK_CLASS(type, pin, invert, deadzone) new OH::MemoizedSensor(new OH::JoystickAxisSensor(new OH::AnalogSensor(pin), deadzone)) -#define INPUTS_COUNT (FINGER_COUNT) - using namespace OpenGloves; #pragma region FingerSensor #if FINGER_THUMB_ENABLED - auto* fingerThumb = FINGER_CLASS(EncodedInput::Type::THUMB, PIN_FINGER_THUMB, FINGER_THUMB_INVERT, CALIBRATION_CURL); + auto* fingerThumb = FINGER_CLASS(IEncodedInput::Type::THUMB, PIN_FINGER_THUMB, FINGER_THUMB_INVERT, CALIBRATION_CURL); #endif #if FINGER_INDEX_ENABLED - auto* fingerIndex = FINGER_CLASS(EncodedInput::Type::INDEX, PIN_FINGER_INDEX, FINGER_INDEX_INVERT, CALIBRATION_CURL); + auto* fingerIndex = FINGER_CLASS(IEncodedInput::Type::INDEX, PIN_FINGER_INDEX, FINGER_INDEX_INVERT, CALIBRATION_CURL); #endif #if FINGER_MIDDLE_ENABLED - auto* fingerMiddle = FINGER_CLASS(EncodedInput::Type::MIDDLE, PIN_FINGER_MIDDLE, FINGER_MIDDLE_INVERT, CALIBRATION_CURL); + auto* fingerMiddle = FINGER_CLASS(IEncodedInput::Type::MIDDLE, PIN_FINGER_MIDDLE, FINGER_MIDDLE_INVERT, CALIBRATION_CURL); #endif #if FINGER_RING_ENABLED - auto* fingerRing = FINGER_CLASS(EncodedInput::Type::RING, PIN_FINGER_RING, FINGER_RING_INVERT, CALIBRATION_CURL); + auto* fingerRing = FINGER_CLASS(IEncodedInput::Type::RING, PIN_FINGER_RING, FINGER_RING_INVERT, CALIBRATION_CURL); #endif #if FINGER_PINKY_ENABLED - auto* fingerPinky = FINGER_CLASS(EncodedInput::Type::PINKY, PIN_FINGER_PINKY, FINGER_PINKY_INVERT, CALIBRATION_CURL); + auto* fingerPinky = FINGER_CLASS(IEncodedInput::Type::PINKY, PIN_FINGER_PINKY, FINGER_PINKY_INVERT, CALIBRATION_CURL); #endif FingerSensor* fingers[FINGER_COUNT] = { @@ -72,63 +70,35 @@ FingerSensor* fingers[FINGER_COUNT] = { OH::MemoizedSensor* joystick[JOYSTICK_COUNT] = { #if JOYSTICK_ENABLED - JOYSTICK_CLASS(EncodedInput::Type::JOY_X, PIN_JOYSTICK_X, JOYSTICK_X_INVERT, JOYSTICK_DEADZONE), - JOYSTICK_CLASS(EncodedInput::Type::JOY_Y, PIN_JOYSTICK_Y, JOYSTICK_Y_INVERT, JOYSTICK_DEADZONE), + JOYSTICK_CLASS(IEncodedInput::Type::JOY_X, PIN_JOYSTICK_X, JOYSTICK_X_INVERT, JOYSTICK_DEADZONE), + JOYSTICK_CLASS(IEncodedInput::Type::JOY_Y, PIN_JOYSTICK_Y, JOYSTICK_Y_INVERT, JOYSTICK_DEADZONE), #endif }; -IEncodedSensor* inputs[INPUTS_COUNT]; -char* encoded_output_string; +std::vector inputs = std::vector(); + +auto communication = new SerialCommunication(&Serial); void setupMode() { - size_t currentSensor = 0; + communication->setup(); for (size_t i = 0; i < FINGER_COUNT; i++) { auto* finger = fingers[i]; - inputs[currentSensor++] = finger; + inputs.push_back(finger); finger->setup(); - finger->enableCalibration(); } for (size_t i = 0; i < JOYSTICK_COUNT; i++) { - // sensors[currentSensor++] = joystick[i]; joystick[i]->setup(); } - - int string_size = 0; - for(size_t i = 0; i < INPUTS_COUNT; i++) { - string_size += inputs[i]->getEncodedSize(); - } - - // Add 1 for new line and 1 for the null terminator. - encoded_output_string = new char[string_size + 1 + 1]; - - Serial.begin(115200); -} - -int encodeAll(char* output, IEncodedSensor* encoders[], size_t count) { - int offset = 0; - // Loop over all of the encoders and encode them to the output string. - for (size_t i = 0; i < count; i++) { - // The offset is the total charecters already added to the string. - offset += encoders[i]->encode(output+offset); - } - - // Add a new line to the end of the encoded string. - output[offset++] = '\n'; - output[offset] = '\0'; - - return offset; } void loopMode() { // update all sensor values - for (int i = 0; i < INPUTS_COUNT; i++) { - auto* sensor = inputs[i]; - sensor->updateValue(); + for (size_t i = 0; i < inputs.size(); i++) { + inputs[i]->updateValue(); } - // encode all sensor values - encodeAll(encoded_output_string, inputs, INPUTS_COUNT); - Serial.print(encoded_output_string); + // send all sensor values + communication->send(inputs); } diff --git a/lib/opengloves_utils/opengloves_protocol.hpp b/lib/opengloves/og_protocol.hpp similarity index 60% rename from lib/opengloves_utils/opengloves_protocol.hpp rename to lib/opengloves/og_protocol.hpp index 417c20bf..3473582d 100644 --- a/lib/opengloves_utils/opengloves_protocol.hpp +++ b/lib/opengloves/og_protocol.hpp @@ -2,7 +2,7 @@ namespace OpenGloves { - struct EncodedInput { + struct IEncodedInput { public: enum Type : char { THUMB = 'A', @@ -22,7 +22,7 @@ namespace OpenGloves CALIBRATE = 'O' }; - EncodedInput(Type type) : type(type) { }; + IEncodedInput(Type type) : type(type) { }; constexpr Type getType() const { return this->type; @@ -34,4 +34,18 @@ namespace OpenGloves private: Type type; }; + + class IEncodedSensor : public IEncodedInput { + public: + IEncodedSensor(Type type) : IEncodedInput(type) { }; + + virtual void setup() = 0; + virtual void updateValue() = 0; + }; + + class ICommunication { + public: + virtual void setup() = 0; + virtual void send(std::vector sensors) = 0; + }; } // namespace OpenGloves diff --git a/lib/opengloves/sensor/og_finger.hpp b/lib/opengloves/sensor/og_finger.hpp index a5c02521..cb1f2be5 100644 --- a/lib/opengloves/sensor/og_finger.hpp +++ b/lib/opengloves/sensor/og_finger.hpp @@ -6,14 +6,14 @@ namespace OpenGloves { class IFinger : public ICalibratedEncodedSensor, public OH::MemoizedSensor { public : - IFinger(OH::CalibratedSensor* sensor, EncodedInput::Type type) + IFinger(OH::CalibratedSensor* sensor, IEncodedInput::Type type) : ICalibratedEncodedSensor(type), OH::MemoizedSensor(sensor) { }; }; class FingerSensor : public IFinger { public: - FingerSensor(OH::CalibratedSensor* sensor, EncodedInput::Type type) : IFinger(sensor, type) { }; + FingerSensor(OH::CalibratedSensor* sensor, IEncodedInput::Type type) : IFinger(sensor, type) { }; void setup() override { this->sensor->setup(); diff --git a/lib/opengloves/sensor/og_sensor.hpp b/lib/opengloves/sensor/og_sensor.hpp index 35e890a6..1a226ff7 100644 --- a/lib/opengloves/sensor/og_sensor.hpp +++ b/lib/opengloves/sensor/og_sensor.hpp @@ -2,17 +2,10 @@ #include #include -#include +#include namespace OpenGloves { - class IEncodedSensor : public EncodedInput { - public: - IEncodedSensor(Type type) : EncodedInput(type) { }; - virtual void setup() = 0; - virtual void updateValue() = 0; - }; - struct ICalibratedEncodedSensor : public IEncodedSensor { public: ICalibratedEncodedSensor(Type type) : IEncodedSensor(type) { }; diff --git a/lib/opengloves_serial/og_serial_commmunications.hpp b/lib/opengloves_serial/og_serial_commmunications.hpp new file mode 100644 index 00000000..292bb80e --- /dev/null +++ b/lib/opengloves_serial/og_serial_commmunications.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +namespace OpenGloves +{ + class SerialCommunication : public ICommunication { + private: + HardwareSerial* serial; + char* buffer = new char[256]; + + public: + SerialCommunication(HardwareSerial* serial) : serial(serial) { }; + + void setup() override { + this->serial->begin(115200); + } + + void send(std::vector sensors) override { + int offset = 0; + // Loop over all of the encoders and encode them to the output string. + for (int i = 0; i < sensors.size(); i++) { + // The offset is the total charecters already added to the string. + offset += sensors[i]->encode(this->buffer + offset); + } + + // Add a new line to the end of the encoded string. + this->buffer[offset++] = '\n'; + this->buffer[offset] = '\0'; + + this->serial->write(this->buffer, offset); + this->serial->flush(); + } + }; +} // namespace OpenGloves From de04be70efa0188fbe4b3bb478e5ae53b21498ff Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Sun, 11 Jun 2023 23:32:27 +0400 Subject: [PATCH 09/16] refactor(OpenGloves): update HAL --- .../mode_configs/opengloves/opengloves.cpp | 41 ++++++++++------- lib/calibration/calibration.hpp | 12 +++-- lib/opengloves/og_protocol.hpp | 11 ++--- lib/opengloves/sensor/og_finger.hpp | 46 +++++-------------- lib/opengloves/sensor/og_sensor.hpp | 33 +++++++++++-- .../og_serial_commmunications.hpp | 22 +++++---- 6 files changed, 92 insertions(+), 73 deletions(-) diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp index a8e758bb..cc0e8df8 100644 --- a/firmware/mode_configs/opengloves/opengloves.cpp +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -29,40 +29,40 @@ using namespace OpenGloves; #pragma region FingerSensor #if FINGER_THUMB_ENABLED - auto* fingerThumb = FINGER_CLASS(IEncodedInput::Type::THUMB, PIN_FINGER_THUMB, FINGER_THUMB_INVERT, CALIBRATION_CURL); + auto* fingerThumbCurl = FINGER_CLASS(IEncodedInput::Type::THUMB, PIN_FINGER_THUMB, FINGER_THUMB_INVERT, CALIBRATION_CURL); #endif #if FINGER_INDEX_ENABLED - auto* fingerIndex = FINGER_CLASS(IEncodedInput::Type::INDEX, PIN_FINGER_INDEX, FINGER_INDEX_INVERT, CALIBRATION_CURL); + auto* fingerIndexCurl = FINGER_CLASS(IEncodedInput::Type::INDEX, PIN_FINGER_INDEX, FINGER_INDEX_INVERT, CALIBRATION_CURL); #endif #if FINGER_MIDDLE_ENABLED - auto* fingerMiddle = FINGER_CLASS(IEncodedInput::Type::MIDDLE, PIN_FINGER_MIDDLE, FINGER_MIDDLE_INVERT, CALIBRATION_CURL); + auto* fingerMiddleCurl = FINGER_CLASS(IEncodedInput::Type::MIDDLE, PIN_FINGER_MIDDLE, FINGER_MIDDLE_INVERT, CALIBRATION_CURL); #endif #if FINGER_RING_ENABLED - auto* fingerRing = FINGER_CLASS(IEncodedInput::Type::RING, PIN_FINGER_RING, FINGER_RING_INVERT, CALIBRATION_CURL); + auto* fingerRingCurl = FINGER_CLASS(IEncodedInput::Type::RING, PIN_FINGER_RING, FINGER_RING_INVERT, CALIBRATION_CURL); #endif #if FINGER_PINKY_ENABLED - auto* fingerPinky = FINGER_CLASS(IEncodedInput::Type::PINKY, PIN_FINGER_PINKY, FINGER_PINKY_INVERT, CALIBRATION_CURL); + auto* fingerPinkyCurl = FINGER_CLASS(IEncodedInput::Type::PINKY, PIN_FINGER_PINKY, FINGER_PINKY_INVERT, CALIBRATION_CURL); #endif FingerSensor* fingers[FINGER_COUNT] = { #if FINGER_THUMB_ENABLED - fingerThumb, + fingerThumbCurl, #endif #if FINGER_INDEX_ENABLED - fingerIndex, + fingerIndexCurl, #endif #if FINGER_MIDDLE_ENABLED - fingerMiddle, + fingerMiddleCurl, #endif #if FINGER_RING_ENABLED - fingerRing, + fingerRingCurl, #endif #if FINGER_PINKY_ENABLED - fingerPinky, + fingerPinkyCurl, #endif }; @@ -75,28 +75,37 @@ OH::MemoizedSensor* joystick[JOYSTICK_COUNT] = { #endif }; -std::vector inputs = std::vector(); +std::vector inputs = std::vector(); +std::vector calibrated = std::vector(); auto communication = new SerialCommunication(&Serial); void setupMode() { - communication->setup(); - for (size_t i = 0; i < FINGER_COUNT; i++) { auto* finger = fingers[i]; - inputs.push_back(finger); finger->setup(); + + #if defined(CALIBRATION_ALWAYS_CALIBRATE) && CALIBRATION_ALWAYS_CALIBRATE + finger->enableCalibration(); + #endif + + inputs.push_back(finger); + calibrated.push_back(finger); } for (size_t i = 0; i < JOYSTICK_COUNT; i++) { - joystick[i]->setup(); + auto* axis = joystick[i]; + axis->setup(); } + + communication->setup(); } void loopMode() { // update all sensor values for (size_t i = 0; i < inputs.size(); i++) { - inputs[i]->updateValue(); + auto* input = inputs[i]; + input->updateValue(); } // send all sensor values diff --git a/lib/calibration/calibration.hpp b/lib/calibration/calibration.hpp index 09297028..5d2e0fba 100644 --- a/lib/calibration/calibration.hpp +++ b/lib/calibration/calibration.hpp @@ -8,18 +8,24 @@ #include namespace OH { - class Calibrated { + struct ICalibrated { + virtual void resetCalibration() = 0; + virtual void enableCalibration() = 0; + virtual void disableCalibration() = 0; + }; + + class Calibrated : public ICalibrated { protected: bool calibrate = false; public: virtual void resetCalibration() = 0; - void enableCalibration() { + void enableCalibration() override { calibrate = true; } - void disableCalibration() { + void disableCalibration() override { calibrate = false; } }; diff --git a/lib/opengloves/og_protocol.hpp b/lib/opengloves/og_protocol.hpp index 3473582d..1189f7bc 100644 --- a/lib/opengloves/og_protocol.hpp +++ b/lib/opengloves/og_protocol.hpp @@ -28,24 +28,23 @@ namespace OpenGloves return this->type; } - virtual size_t getEncodedSize() const = 0; - virtual int encode(char* buffer) const = 0; - private: Type type; }; - class IEncodedSensor : public IEncodedInput { + class IStringEncodedSensor : public IEncodedInput { public: - IEncodedSensor(Type type) : IEncodedInput(type) { }; + IStringEncodedSensor(Type type) : IEncodedInput(type) { }; virtual void setup() = 0; virtual void updateValue() = 0; + + virtual size_t encodeString(char* buffer) = 0; }; class ICommunication { public: virtual void setup() = 0; - virtual void send(std::vector sensors) = 0; + virtual void send(std::vector sensors) = 0; }; } // namespace OpenGloves diff --git a/lib/opengloves/sensor/og_finger.hpp b/lib/opengloves/sensor/og_finger.hpp index cb1f2be5..71370895 100644 --- a/lib/opengloves/sensor/og_finger.hpp +++ b/lib/opengloves/sensor/og_finger.hpp @@ -4,45 +4,21 @@ namespace OpenGloves { - class IFinger : public ICalibratedEncodedSensor, public OH::MemoizedSensor { + class FingerSensor : public StringEncodedMemoizedSensor, public virtual OH::ICalibrated { public : - IFinger(OH::CalibratedSensor* sensor, IEncodedInput::Type type) - : ICalibratedEncodedSensor(type), OH::MemoizedSensor(sensor) { }; - }; - - class FingerSensor : public IFinger - { - public: - FingerSensor(OH::CalibratedSensor* sensor, IEncodedInput::Type type) : IFinger(sensor, type) { }; - - void setup() override { - this->sensor->setup(); - } - - void updateValue() override { - this->value = this->sensor->getValue(); - } - - void resetCalibration() override { - static_cast*>(this->sensor)->resetCalibration(); - } - - void enableCalibration() override { - static_cast*>(this->sensor)->enableCalibration(); - } + FingerSensor(OH::CalibratedSensor* sensor, IEncodedInput::Type type) : StringEncodedMemoizedSensor(sensor, type) { }; - void disableCalibration() override { - static_cast*>(this->sensor)->disableCalibration(); - } + void resetCalibration() override { + static_cast*>(this->sensor)->resetCalibration(); + } - size_t getEncodedSize() const override { - // Encode string size = AXXXX + '\0' - return 6; - } + void enableCalibration() override { + static_cast*>(this->sensor)->enableCalibration(); + } - int encode(char* buffer) const override { - return snprintf(buffer, this->getEncodedSize(), "%c%04d", this->getType(), this->value); - } + void disableCalibration() override { + static_cast*>(this->sensor)->disableCalibration(); + } }; // TODO: add splay finger sensor diff --git a/lib/opengloves/sensor/og_sensor.hpp b/lib/opengloves/sensor/og_sensor.hpp index 1a226ff7..65a7c539 100644 --- a/lib/opengloves/sensor/og_sensor.hpp +++ b/lib/opengloves/sensor/og_sensor.hpp @@ -6,11 +6,34 @@ namespace OpenGloves { - struct ICalibratedEncodedSensor : public IEncodedSensor { + template + class StringEncodedMemoizedSensor : public IStringEncodedSensor, public OH::MemoizedSensor<_Tp> { public: - ICalibratedEncodedSensor(Type type) : IEncodedSensor(type) { }; - virtual void resetCalibration() = 0; - virtual void enableCalibration() = 0; - virtual void disableCalibration() = 0; + StringEncodedMemoizedSensor(OH::ISensor* sensor, IEncodedInput::Type type) + : IStringEncodedSensor(type), OH::MemoizedSensor(sensor) { }; + + void setup() override { + this->sensor->setup(); + } + + void updateValue() override { + this->value = this->sensor->getValue(); + } + + size_t encodeString(char* buffer) override; }; + + template <> + size_t StringEncodedMemoizedSensor::encodeString(char* buffer) { + return snprintf(buffer, 6, "%c%d", this->getType(), this->getValue()); + } + + template <> + size_t StringEncodedMemoizedSensor::encodeString(char* buffer) { + if (value) { + buffer[0] = this->getType(); + } + return value ? 1 : 0; + } + } // namespace OpenGloves diff --git a/lib/opengloves_serial/og_serial_commmunications.hpp b/lib/opengloves_serial/og_serial_commmunications.hpp index 292bb80e..ad50ae9e 100644 --- a/lib/opengloves_serial/og_serial_commmunications.hpp +++ b/lib/opengloves_serial/og_serial_commmunications.hpp @@ -17,20 +17,26 @@ namespace OpenGloves this->serial->begin(115200); } - void send(std::vector sensors) override { - int offset = 0; + void send(std::vector sensors) override { + // Encode all of the sensors into a single string. + size_t length = encodeAll(buffer, sensors); + // Send the encoded string over serial. + this->serial->write(buffer, length); + } + + static size_t encodeAll(char* buffer, std::vector sensors) { + size_t offset = 0; // Loop over all of the encoders and encode them to the output string. - for (int i = 0; i < sensors.size(); i++) { + for (size_t i = 0; i < sensors.size(); i++) { // The offset is the total charecters already added to the string. - offset += sensors[i]->encode(this->buffer + offset); + offset += sensors[i]->encodeString(buffer + offset); } // Add a new line to the end of the encoded string. - this->buffer[offset++] = '\n'; - this->buffer[offset] = '\0'; + buffer[offset++] = '\n'; + buffer[offset] = '\0'; - this->serial->write(this->buffer, offset); - this->serial->flush(); + return offset; } }; } // namespace OpenGloves From 886354f75fce2c8a4f929a31753ada2170aa589d Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Mon, 12 Jun 2023 14:54:30 +0400 Subject: [PATCH 10/16] feat(OpenGloves): add Joystick sensors --- .../mode_configs/opengloves/opengloves.cpp | 6 +++-- lib/opengloves/og_protocol.hpp | 5 ++-- lib/opengloves/sensor/og_sensor.hpp | 23 +++++++++++++++---- .../og_serial_commmunications.hpp | 4 ++-- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp index cc0e8df8..d97b4d83 100644 --- a/firmware/mode_configs/opengloves/opengloves.cpp +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -22,7 +22,7 @@ #define JOYSTICK_ENABLED (PIN_JOYSTICK_X != -1 && PIN_JOYSTICK_Y != -1) #define JOYSTICK_COUNT (JOYSTICK_ENABLED ? 2 : 0) -#define JOYSTICK_CLASS(type, pin, invert, deadzone) new OH::MemoizedSensor(new OH::JoystickAxisSensor(new OH::AnalogSensor(pin), deadzone)) +#define JOYSTICK_CLASS(type, pin, invert, deadzone) new StringEncodedMemoizedSensor(new OH::JoystickAxisSensor(new OH::AnalogSensor(pin), deadzone), type) using namespace OpenGloves; @@ -68,7 +68,7 @@ FingerSensor* fingers[FINGER_COUNT] = { #pragma endregion -OH::MemoizedSensor* joystick[JOYSTICK_COUNT] = { +StringEncodedMemoizedSensor* joystick[JOYSTICK_COUNT] = { #if JOYSTICK_ENABLED JOYSTICK_CLASS(IEncodedInput::Type::JOY_X, PIN_JOYSTICK_X, JOYSTICK_X_INVERT, JOYSTICK_DEADZONE), JOYSTICK_CLASS(IEncodedInput::Type::JOY_Y, PIN_JOYSTICK_Y, JOYSTICK_Y_INVERT, JOYSTICK_DEADZONE), @@ -96,6 +96,8 @@ void setupMode() { for (size_t i = 0; i < JOYSTICK_COUNT; i++) { auto* axis = joystick[i]; axis->setup(); + + inputs.push_back(axis); } communication->setup(); diff --git a/lib/opengloves/og_protocol.hpp b/lib/opengloves/og_protocol.hpp index 1189f7bc..89270585 100644 --- a/lib/opengloves/og_protocol.hpp +++ b/lib/opengloves/og_protocol.hpp @@ -39,12 +39,13 @@ namespace OpenGloves virtual void setup() = 0; virtual void updateValue() = 0; - virtual size_t encodeString(char* buffer) = 0; + virtual size_t getEncodedLength() const = 0; + virtual size_t encodeString(char* buffer) const = 0; }; class ICommunication { public: virtual void setup() = 0; - virtual void send(std::vector sensors) = 0; + virtual void send(std::vector &sensors) = 0; }; } // namespace OpenGloves diff --git a/lib/opengloves/sensor/og_sensor.hpp b/lib/opengloves/sensor/og_sensor.hpp index 65a7c539..292a35c9 100644 --- a/lib/opengloves/sensor/og_sensor.hpp +++ b/lib/opengloves/sensor/og_sensor.hpp @@ -20,20 +20,33 @@ namespace OpenGloves this->value = this->sensor->getValue(); } - size_t encodeString(char* buffer) override; + size_t getEncodedLength() const override; + + size_t encodeString(char* buffer) const override; }; template <> - size_t StringEncodedMemoizedSensor::encodeString(char* buffer) { - return snprintf(buffer, 6, "%c%d", this->getType(), this->getValue()); + size_t StringEncodedMemoizedSensor::getEncodedLength() const { + return 6; + } + + template <> + size_t StringEncodedMemoizedSensor::encodeString(char* buffer) const { + // Format as "Axxxxx", where A is the type and xxxxx is the value without leading zeros. + return snprintf(buffer, this->getEncodedLength(), "%c%d", this->getType(), this->value); + } + + template <> + size_t StringEncodedMemoizedSensor::getEncodedLength() const { + return 1; } template <> - size_t StringEncodedMemoizedSensor::encodeString(char* buffer) { + size_t StringEncodedMemoizedSensor::encodeString(char* buffer) const { if (value) { buffer[0] = this->getType(); } - return value ? 1 : 0; + return value ? this->getEncodedLength() : 0; } } // namespace OpenGloves diff --git a/lib/opengloves_serial/og_serial_commmunications.hpp b/lib/opengloves_serial/og_serial_commmunications.hpp index ad50ae9e..dc6a0c4d 100644 --- a/lib/opengloves_serial/og_serial_commmunications.hpp +++ b/lib/opengloves_serial/og_serial_commmunications.hpp @@ -17,14 +17,14 @@ namespace OpenGloves this->serial->begin(115200); } - void send(std::vector sensors) override { + void send(std::vector &sensors) override { // Encode all of the sensors into a single string. size_t length = encodeAll(buffer, sensors); // Send the encoded string over serial. this->serial->write(buffer, length); } - static size_t encodeAll(char* buffer, std::vector sensors) { + static size_t encodeAll(char* buffer, std::vector &sensors) { size_t offset = 0; // Loop over all of the encoders and encode them to the output string. for (size_t i = 0; i < sensors.size(); i++) { From 6b6f44e513d6a2eaeec8f18d86f4fe9bdd9d8aec Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Mon, 12 Jun 2023 16:40:16 +0400 Subject: [PATCH 11/16] feat: add button DigitalSensor --- lib/arduino/sensor/digital.hpp | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 lib/arduino/sensor/digital.hpp diff --git a/lib/arduino/sensor/digital.hpp b/lib/arduino/sensor/digital.hpp new file mode 100644 index 00000000..7cf2290a --- /dev/null +++ b/lib/arduino/sensor/digital.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +namespace OH +{ + typedef ISensor IDigitalSensor; + + template + class DigitalSensor : public IDigitalSensor + { + private: + uint8_t pin; + uint8_t _pinMode; + + public: + DigitalSensor(uint8_t pin, uint8_t pinMode) : pin(pin), _pinMode(pinMode) { + // static_assert( + // _pinMode == INPUT || _pinMode == INPUT_PULLUP || _pinMode == INPUT_PULLDOWN, + // "pinMode must be INPUT, INPUT_PULLUP or INPUT_PULLDOWN" + // ); + } + + void setup(void) + { + pinMode(this->pin, this->_pinMode); + }; + + bool getValue(void) override; + }; + + template <> + bool DigitalSensor::getValue(void) + { + return digitalRead(this->pin) == HIGH; + } + + template <> + bool DigitalSensor::getValue(void) + { + return digitalRead(this->pin) == LOW; + } +} // namespace OH From 95262acdb831fb3be73309c5e1797a97d35e19f2 Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Mon, 12 Jun 2023 18:28:07 +0400 Subject: [PATCH 12/16] feat(OpenGloves): add buttons --- .../mode_configs/opengloves/opengloves.cpp | 40 ++++++++++++++++++- ini/opengloves.ini | 27 +++++++++++++ lib/arduino/sensor/digital.hpp | 9 +---- lib/opengloves/sensor/og_sensor.hpp | 4 +- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp index d97b4d83..1e732414 100644 --- a/firmware/mode_configs/opengloves/opengloves.cpp +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -16,14 +17,20 @@ #define FINGER_RING_ENABLED (PIN_FINGER_RING != -1) #define FINGER_PINKY_ENABLED (PIN_FINGER_PINKY != -1) #define FINGER_COUNT (FINGER_THUMB_ENABLED + FINGER_INDEX_ENABLED + FINGER_MIDDLE_ENABLED + FINGER_RING_ENABLED + FINGER_PINKY_ENABLED) - #define FINGER_CLASS(type, pin, invert, calib) new FingerSensor(new OH::CalibratedSensor(new OH::AnalogSensor(pin), new calib()), type) #define JOYSTICK_ENABLED (PIN_JOYSTICK_X != -1 && PIN_JOYSTICK_Y != -1) #define JOYSTICK_COUNT (JOYSTICK_ENABLED ? 2 : 0) - #define JOYSTICK_CLASS(type, pin, invert, deadzone) new StringEncodedMemoizedSensor(new OH::JoystickAxisSensor(new OH::AnalogSensor(pin), deadzone), type) +#define BUTTON_A_ENABLED (PIN_BUTTON_A != -1) +#define BUTTON_B_ENABLED (PIN_BUTTON_B != -1) +#define BUTTON_MENU_ENABLED (PIN_BUTTON_MENU != -1) +#define BUTTON_CALIBRATE_ENABLED (PIN_BUTTON_CALIBRATE != -1) +#define BUTTON_JOYSTICK_ENABLED (JOYSTICK_ENABLED && (PIN_BUTTON_JOYSTICK != -1)) +#define BUTTON_COUNT (BUTTON_A_ENABLED + BUTTON_B_ENABLED + BUTTON_MENU_ENABLED + BUTTON_CALIBRATE_ENABLED + BUTTON_JOYSTICK_ENABLED) +#define BUTTON_CLASS(type, pin, invert) new StringEncodedMemoizedSensor(new OH::DigitalSensor(pin), type) + using namespace OpenGloves; #pragma region FingerSensor @@ -75,6 +82,28 @@ StringEncodedMemoizedSensor* joystick[JOYSTICK_COUNT] = { #endif }; +#if BUTTON_CALIBRATE_ENABLED +StringEncodedMemoizedSensor* calibrateButton = BUTTON_CLASS(IEncodedInput::Type::CALIBRATE, PIN_BUTTON_CALIBRATE, BUTTON_CALIBRATE_INVERT); +#endif + +std::vector*> buttons = std::vector*>{ +#if BUTTON_A_ENABLED + BUTTON_CLASS(IEncodedInput::Type::A_BTN, PIN_BUTTON_A, BUTTON_A_INVERT), +#endif +#if BUTTON_B_ENABLED + BUTTON_CLASS(IEncodedInput::Type::B_BTN, PIN_BUTTON_B, BUTTON_B_INVERT), +#endif +#if BUTTON_MENU_ENABLED + BUTTON_CLASS(IEncodedInput::Type::MENU, PIN_BUTTON_MENU, BUTTON_MENU_INVERT), +#endif +#if BUTTON_JOYSTICK_ENABLED + BUTTON_CLASS(IEncodedInput::Type::JOY_BTN, PIN_BUTTON_JOYSTICK, BUTTON_JOYSTICK_INVERT), +#endif +#if BUTTON_CALIBRATE_ENABLED + calibrateButton, +#endif +}; + std::vector inputs = std::vector(); std::vector calibrated = std::vector(); @@ -100,6 +129,13 @@ void setupMode() { inputs.push_back(axis); } + for (size_t i = 0; i < BUTTON_COUNT; i++) { + auto* button = buttons[i]; + button->setup(); + + inputs.push_back(button); + } + communication->setup(); } diff --git a/ini/opengloves.ini b/ini/opengloves.ini index 9c4dcca1..9ef0551e 100644 --- a/ini/opengloves.ini +++ b/ini/opengloves.ini @@ -19,6 +19,22 @@ build_flags = ${common.build_flags} -D JOYSTICK_Y_INVERT=false -D JOYSTICK_DEADZONE=0.1 + -D BUTTON_A_INVERT=false + -D BUTTON_B_INVERT=false + -D BUTTON_MENU_INVERT=false + -D BUTTON_JOYSTICK_INVERT=false + -D BUTTON_CALIBRATE_INVERT=false + -D BUTTON_TRIGGER_INVERT=false + -D BUTTON_GRAB_INVERT=false + -D BUTTON_PINCH_INVERT=false + + -D GESTURE_TRIGGER=false + -D GESTURE_GRAB=false + -D GESTURE_PINCH=false + + ; Calibration + -D CALIBRATION_ALWAYS_CALIBRATE=false + ; Pins configuration ; If pin set to -1, then it will be ignored -D PIN_FINGER_THUMB=32 @@ -26,8 +42,19 @@ build_flags = ${common.build_flags} -D PIN_FINGER_MIDDLE=34 -D PIN_FINGER_RING=39 -D PIN_FINGER_PINKY=36 + -D PIN_JOYSTICK_X=33 -D PIN_JOYSTICK_Y=25 + + -D PIN_BUTTON_A=27 + -D PIN_BUTTON_B=14 + -D PIN_BUTTON_JOYSTICK=26 + -D PIN_BUTTON_MENU=27 + -D PIN_BUTTON_CALIBRATE=12 + -D PIN_BUTTON_TRIGGER=12 ; unused if GESTURE_TRIGGER is true + -D PIN_BUTTON_GRAB=13 ; unused if GESTURE_GRAB is true + -D PIN_BUTTON_PINCH=23 ; unused if GESTURE_PINCH is true + build_unflags = ${common.build_unflags} build_src_filter = ${common.build_src_filter} lib_deps = ${common.lib_deps} diff --git a/lib/arduino/sensor/digital.hpp b/lib/arduino/sensor/digital.hpp index 7cf2290a..abd812d2 100644 --- a/lib/arduino/sensor/digital.hpp +++ b/lib/arduino/sensor/digital.hpp @@ -12,19 +12,14 @@ namespace OH { private: uint8_t pin; - uint8_t _pinMode; public: - DigitalSensor(uint8_t pin, uint8_t pinMode) : pin(pin), _pinMode(pinMode) { - // static_assert( - // _pinMode == INPUT || _pinMode == INPUT_PULLUP || _pinMode == INPUT_PULLDOWN, - // "pinMode must be INPUT, INPUT_PULLUP or INPUT_PULLDOWN" - // ); + DigitalSensor(uint8_t pin) : pin(pin) { } void setup(void) { - pinMode(this->pin, this->_pinMode); + pinMode(this->pin, INPUT); }; bool getValue(void) override; diff --git a/lib/opengloves/sensor/og_sensor.hpp b/lib/opengloves/sensor/og_sensor.hpp index 292a35c9..1ad6dfcf 100644 --- a/lib/opengloves/sensor/og_sensor.hpp +++ b/lib/opengloves/sensor/og_sensor.hpp @@ -9,8 +9,8 @@ namespace OpenGloves template class StringEncodedMemoizedSensor : public IStringEncodedSensor, public OH::MemoizedSensor<_Tp> { public: - StringEncodedMemoizedSensor(OH::ISensor* sensor, IEncodedInput::Type type) - : IStringEncodedSensor(type), OH::MemoizedSensor(sensor) { }; + StringEncodedMemoizedSensor(OH::ISensor<_Tp>* sensor, IEncodedInput::Type type) + : IStringEncodedSensor(type), OH::MemoizedSensor<_Tp>(sensor) { }; void setup() override { this->sensor->setup(); From 33023bc963a8ec1587dea8b234c6b03424872019 Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Mon, 12 Jun 2023 19:08:11 +0400 Subject: [PATCH 13/16] feat(OpenGloves): respect update rate --- .../mode_configs/opengloves/opengloves.cpp | 34 ++++++++++++++++--- ini/opengloves.ini | 8 +++-- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp index 1e732414..7827947d 100644 --- a/firmware/mode_configs/opengloves/opengloves.cpp +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -26,11 +26,19 @@ #define BUTTON_A_ENABLED (PIN_BUTTON_A != -1) #define BUTTON_B_ENABLED (PIN_BUTTON_B != -1) #define BUTTON_MENU_ENABLED (PIN_BUTTON_MENU != -1) -#define BUTTON_CALIBRATE_ENABLED (PIN_BUTTON_CALIBRATE != -1) #define BUTTON_JOYSTICK_ENABLED (JOYSTICK_ENABLED && (PIN_BUTTON_JOYSTICK != -1)) -#define BUTTON_COUNT (BUTTON_A_ENABLED + BUTTON_B_ENABLED + BUTTON_MENU_ENABLED + BUTTON_CALIBRATE_ENABLED + BUTTON_JOYSTICK_ENABLED) +#define BUTTON_CALIBRATE_ENABLED (PIN_BUTTON_CALIBRATE != -1) +#define BUTTON_TRIGGER_ENABLED (!GESTURE_TRIGGER_ENABLED && (PIN_BUTTON_TRIGGER != -1)) +#define BUTTON_GRAB_ENABLED (!GESTURE_GRAB_ENABLED && (PIN_BUTTON_GRAB != -1)) +#define BUTTON_PINCH_ENABLED (!GESTURE_PINCH_ENABLED && (PIN_BUTTON_PINCH != -1)) +#define BUTTON_COUNT (BUTTON_A_ENABLED + BUTTON_B_ENABLED + BUTTON_MENU_ENABLED + BUTTON_JOYSTICK_ENABLED + BUTTON_CALIBRATE_ENABLED + BUTTON_TRIGGER_ENABLED + BUTTON_GRAB_ENABLED + BUTTON_PINCH_ENABLED) #define BUTTON_CLASS(type, pin, invert) new StringEncodedMemoizedSensor(new OH::DigitalSensor(pin), type) +#ifndef UPDATE_RATE +#define UPDATE_RATE 90 +#endif +#define UPDATE_INTERVAL (1000 / UPDATE_RATE) + using namespace OpenGloves; #pragma region FingerSensor @@ -93,15 +101,24 @@ std::vector*> buttons = std::vector inputs = std::vector(); @@ -140,6 +157,8 @@ void setupMode() { } void loopMode() { + auto now = millis(); + // update all sensor values for (size_t i = 0; i < inputs.size(); i++) { auto* input = inputs[i]; @@ -148,4 +167,9 @@ void loopMode() { // send all sensor values communication->send(inputs); + + auto elapsed = millis() - now; + if (elapsed < UPDATE_INTERVAL) { + delay(UPDATE_INTERVAL - elapsed); + } } diff --git a/ini/opengloves.ini b/ini/opengloves.ini index 9ef0551e..9f22e627 100644 --- a/ini/opengloves.ini +++ b/ini/opengloves.ini @@ -28,9 +28,9 @@ build_flags = ${common.build_flags} -D BUTTON_GRAB_INVERT=false -D BUTTON_PINCH_INVERT=false - -D GESTURE_TRIGGER=false - -D GESTURE_GRAB=false - -D GESTURE_PINCH=false + -D GESTURE_TRIGGER_ENABLED=true + -D GESTURE_GRAB_ENABLED=true + -D GESTURE_PINCH_ENABLED=true ; Calibration -D CALIBRATION_ALWAYS_CALIBRATE=false @@ -55,6 +55,8 @@ build_flags = ${common.build_flags} -D PIN_BUTTON_GRAB=13 ; unused if GESTURE_GRAB is true -D PIN_BUTTON_PINCH=23 ; unused if GESTURE_PINCH is true + -D UPDATE_RATE=90 ; sensors update rate in Hz + build_unflags = ${common.build_unflags} build_src_filter = ${common.build_src_filter} lib_deps = ${common.lib_deps} From 9b62c3892b1c9dc7a37ea2f1ca50e8c884e3ee28 Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Mon, 12 Jun 2023 21:40:14 +0400 Subject: [PATCH 14/16] test(OpenGloves): cover sensors --- lib/calibration/calibration.hpp | 8 +- lib/opengloves/sensor/og_finger.hpp | 13 ++- lib/opengloves/sensor/og_joystick.hpp | 8 -- lib/sensor/sensor.hpp | 6 +- test/test_opengloves/main.cpp | 112 ++++++++++++++++++++++++++ test/test_opengloves_finger/main.cpp | 110 +++++++++++++++++++++++++ test/test_sensor/main.cpp | 45 ++++++++++- 7 files changed, 283 insertions(+), 19 deletions(-) delete mode 100644 lib/opengloves/sensor/og_joystick.hpp create mode 100644 test/test_opengloves/main.cpp create mode 100644 test/test_opengloves_finger/main.cpp diff --git a/lib/calibration/calibration.hpp b/lib/calibration/calibration.hpp index 5d2e0fba..ae94fcf3 100644 --- a/lib/calibration/calibration.hpp +++ b/lib/calibration/calibration.hpp @@ -31,14 +31,14 @@ namespace OH { }; template - struct Calibrator { + struct ICalibrator { virtual void reset() = 0; virtual void update(_Tp input) = 0; virtual _Tp calibrate(_Tp input) const = 0; }; template - class MinMaxCalibrator : public Calibrator<_Tp> { + class MinMaxCalibrator : public ICalibrator<_Tp> { public: MinMaxCalibrator() : value_min(output_max), value_max(output_min) {} @@ -81,7 +81,7 @@ namespace OH { }; template - class CenterPointDeviationCalibrator : public Calibrator<_Tp> { + class CenterPointDeviationCalibrator : public ICalibrator<_Tp> { public: CenterPointDeviationCalibrator() : range_min(sensor_max), range_max(0) { #warning "CenterPointDeviationCalibrator is untested and may not work as expected." @@ -118,7 +118,7 @@ namespace OH { }; template - class FixedCenterPointDeviationCalibrator : public Calibrator<_Tp> { + class FixedCenterPointDeviationCalibrator : public ICalibrator<_Tp> { public: void reset() {} void update(_Tp input) {} diff --git a/lib/opengloves/sensor/og_finger.hpp b/lib/opengloves/sensor/og_finger.hpp index 71370895..1a64ccfd 100644 --- a/lib/opengloves/sensor/og_finger.hpp +++ b/lib/opengloves/sensor/og_finger.hpp @@ -4,9 +4,18 @@ namespace OpenGloves { - class FingerSensor : public StringEncodedMemoizedSensor, public virtual OH::ICalibrated { + class IFinger : public StringEncodedMemoizedSensor, public virtual OH::ICalibrated { public : - FingerSensor(OH::CalibratedSensor* sensor, IEncodedInput::Type type) : StringEncodedMemoizedSensor(sensor, type) { }; + IFinger(OH::CalibratedSensor* sensor, IEncodedInput::Type type) : StringEncodedMemoizedSensor(sensor, type) { }; + + uint16_t getCurl() { + return this->getValue(); + } + }; + + class FingerSensor : public IFinger { + public : + FingerSensor(OH::CalibratedSensor* sensor, IEncodedInput::Type type) : IFinger(sensor, type) { }; void resetCalibration() override { static_cast*>(this->sensor)->resetCalibration(); diff --git a/lib/opengloves/sensor/og_joystick.hpp b/lib/opengloves/sensor/og_joystick.hpp deleted file mode 100644 index 3d6f63c2..00000000 --- a/lib/opengloves/sensor/og_joystick.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "og_sensor.hpp" - -namespace OpenGloves -{ - // typedef SingleAnalogValueEncodedSensor EncidedJoystickSensor; -} // namespace OpenGloves diff --git a/lib/sensor/sensor.hpp b/lib/sensor/sensor.hpp index 7c27608b..93289b5f 100644 --- a/lib/sensor/sensor.hpp +++ b/lib/sensor/sensor.hpp @@ -83,7 +83,7 @@ namespace OH class CalibratedSensor : public ISensor<_Tp>, public Calibrated { protected: ISensor<_Tp>* sensor; - Calibrator<_Tp>* calibrator; + ICalibrator<_Tp>* calibrator; _Tp getCalibratedValue() { auto value = this->sensor->getValue(); @@ -98,9 +98,9 @@ namespace OH public: /** * @param sensor Sensor to be decorated - * @param calibrator Calibrator algorithm to be used + * @param calibrator ICalibrator algorithm to be used */ - CalibratedSensor(ISensor<_Tp>* sensor, Calibrator<_Tp>* calibrator) : sensor(sensor), calibrator(calibrator) {}; + CalibratedSensor(ISensor<_Tp>* sensor, ICalibrator<_Tp>* calibrator) : sensor(sensor), calibrator(calibrator) {}; void setup() override { this->sensor->setup(); diff --git a/test/test_opengloves/main.cpp b/test/test_opengloves/main.cpp new file mode 100644 index 00000000..f8826c4e --- /dev/null +++ b/test/test_opengloves/main.cpp @@ -0,0 +1,112 @@ +#include +#include + +using namespace OpenGloves; + +class TestAnalogSensor : public OH::ISensor { + private: + uint16_t count = 0; + + public: + int setupCounter = 0; + + void setup() override { + this->setupCounter++; + }; + + uint16_t getValue() override { + return ++this->count; + }; +}; + +class TestBinarySensor : public OH::ISensor { + public: + bool value = false; + int setupCounter = 0; + + void setup() override { + this->setupCounter++; + }; + + bool getValue() override { + return this->value; + }; +}; + +void test_string_encoded_sensor_uint16(void) { + auto inner = new TestAnalogSensor(); + auto sensor = new StringEncodedMemoizedSensor(inner, IEncodedInput::Type::INDEX); + + TEST_ASSERT_EQUAL_INT(0, inner->setupCounter); + sensor->setup(); + TEST_ASSERT_EQUAL_INT(1, inner->setupCounter); + + TEST_ASSERT_EQUAL_INT(0, sensor->getValue()); + TEST_ASSERT_EQUAL_INT(0, sensor->getValue()); + + sensor->updateValue(); + + TEST_ASSERT_EQUAL_INT(1, sensor->getValue()); + TEST_ASSERT_EQUAL_INT(1, sensor->getValue()); + + char buffer[6]; + TEST_ASSERT_EQUAL_INT(2, sensor->encodeString(buffer)); + TEST_ASSERT_EQUAL_STRING("B1", buffer); +} + +void test_string_encoded_sensor_bool(void) { + auto inner = new TestBinarySensor(); + auto sensor = new StringEncodedMemoizedSensor(inner, IEncodedInput::Type::A_BTN); + + TEST_ASSERT_EQUAL_INT(0, inner->setupCounter); + sensor->setup(); + TEST_ASSERT_EQUAL_INT(1, inner->setupCounter); + + TEST_ASSERT_FALSE(sensor->getValue()); + + char buffer[1]; + TEST_ASSERT_EQUAL_INT(0, sensor->encodeString(buffer)); + TEST_ASSERT_EQUAL_STRING("", buffer); + + sensor->updateValue(); + + TEST_ASSERT_FALSE(sensor->getValue()); + + inner->value = true; + + TEST_ASSERT_FALSE(sensor->getValue()); + + sensor->updateValue(); + + TEST_ASSERT_TRUE(sensor->getValue()); + + TEST_ASSERT_EQUAL_INT(1, sensor->encodeString(buffer)); + TEST_ASSERT_EQUAL_STRING("J", buffer); +} + +int process(void) { + UNITY_BEGIN(); + + RUN_TEST(test_string_encoded_sensor_uint16); + RUN_TEST(test_string_encoded_sensor_bool); + + return UNITY_END(); +} + +#ifdef ARDUINO + +#include + +void setup(void) { + process(); +} + +void loop(void) {} + +#else + +int main(int argc, char** argv) { + return process(); +} + +#endif diff --git a/test/test_opengloves_finger/main.cpp b/test/test_opengloves_finger/main.cpp new file mode 100644 index 00000000..bfb5a7cc --- /dev/null +++ b/test/test_opengloves_finger/main.cpp @@ -0,0 +1,110 @@ +#include +#include + +using namespace OpenGloves; + +class TestAnalogSensor : public OH::ISensor { + private: + uint16_t count = 0; + + public: + int setupCounter = 0; + + void setup() override { + this->setupCounter++; + }; + + uint16_t getValue() override { + return ++this->count; + }; +}; + +class DummyCalibrator : public OH::ICalibrator { + public: + uint8_t resetCounter = 0; + uint16_t calibrated = 0; + + void reset() override { + this->resetCounter++; + this->calibrated = 0; + }; + void update(uint16_t input) override { + this->calibrated = input; + }; + uint16_t calibrate(uint16_t input) const override { + return calibrated; + }; +}; + +void test_finger_sensor_curl(void) { + auto* inner = new TestAnalogSensor(); + auto* calibrator = new DummyCalibrator(); + auto* calibrated = new OH::CalibratedSensor(inner, calibrator); + auto* sensor = new FingerSensor(calibrated, IEncodedInput::Type::INDEX); + + TEST_ASSERT_EQUAL_INT(0, inner->setupCounter); + sensor->setup(); + TEST_ASSERT_EQUAL_INT(1, inner->setupCounter); + + TEST_ASSERT_EQUAL_INT(0, sensor->getValue()); + TEST_ASSERT_EQUAL_INT(0, sensor->getCurl()); + + sensor->updateValue(); + + TEST_ASSERT_EQUAL_INT(0, sensor->getValue()); + TEST_ASSERT_EQUAL_INT(0, sensor->getCurl()); + + calibrator->calibrated = 100; + + TEST_ASSERT_EQUAL_INT(0, sensor->getValue()); + TEST_ASSERT_EQUAL_INT(0, sensor->getCurl()); + + sensor->updateValue(); + + TEST_ASSERT_EQUAL_INT(100, sensor->getValue()); + TEST_ASSERT_EQUAL_INT(100, sensor->getCurl()); + + TEST_ASSERT_EQUAL_INT(0, calibrator->resetCounter); + sensor->resetCalibration(); + TEST_ASSERT_EQUAL_INT(1, calibrator->resetCounter); + + sensor->enableCalibration(); + sensor->updateValue(); + TEST_ASSERT_EQUAL_INT(3, sensor->getValue()); + TEST_ASSERT_EQUAL_INT(3, sensor->getCurl()); + + sensor->updateValue(); + TEST_ASSERT_EQUAL_INT(4, sensor->getValue()); + TEST_ASSERT_EQUAL_INT(4, sensor->getCurl()); + + sensor->disableCalibration(); + sensor->updateValue(); + TEST_ASSERT_EQUAL_INT(4, sensor->getValue()); + TEST_ASSERT_EQUAL_INT(4, sensor->getCurl()); +} + +int process(void) { + UNITY_BEGIN(); + + RUN_TEST(test_finger_sensor_curl); + + return UNITY_END(); +} + +#ifdef ARDUINO + +#include + +void setup(void) { + process(); +} + +void loop(void) {} + +#else + +int main(int argc, char** argv) { + return process(); +} + +#endif diff --git a/test/test_sensor/main.cpp b/test/test_sensor/main.cpp index dd033ad8..0dd68966 100644 --- a/test/test_sensor/main.cpp +++ b/test/test_sensor/main.cpp @@ -3,7 +3,7 @@ using namespace OH; -class TestSensor : public ISensor { +class TestAnalogSensor : public ISensor { private: int count = 0; @@ -20,7 +20,7 @@ class TestSensor : public ISensor { }; void test_memoized_sensor(void) { - auto inner = new TestSensor(); + auto inner = new TestAnalogSensor(); auto sensor = new MemoizedSensor(inner); TEST_ASSERT_EQUAL_INT(0, inner->setupCounter); @@ -36,10 +36,51 @@ void test_memoized_sensor(void) { TEST_ASSERT_EQUAL_INT(1, sensor->getValue()); } +class DummyCalibrator : public ICalibrator { + public: + uint8_t resetCounter = 0; + int calibrated = 0; + + void reset() override { + this->resetCounter++; + this->calibrated = 0; + }; + void update(int input) override { + this->calibrated = input; + }; + int calibrate(int input) const override { + return calibrated; + }; +}; + +void test_calibrated_sensor(void) { + auto inner = new TestAnalogSensor(); + auto calibrator = new DummyCalibrator(); + auto sensor = new CalibratedSensor(inner, calibrator); + + TEST_ASSERT_EQUAL_INT(0, inner->setupCounter); + sensor->setup(); + TEST_ASSERT_EQUAL_INT(1, inner->setupCounter); + + calibrator->update(-1); + TEST_ASSERT_EQUAL_INT(-1, sensor->getValue()); + + sensor->enableCalibration(); + TEST_ASSERT_EQUAL_INT(2, sensor->getValue()); + + sensor->disableCalibration(); + TEST_ASSERT_EQUAL_INT(2, sensor->getValue()); + + sensor->resetCalibration(); + TEST_ASSERT_EQUAL_INT(0, sensor->getValue()); + TEST_ASSERT_EQUAL_INT(1, calibrator->resetCounter); +} + int process(void) { UNITY_BEGIN(); RUN_TEST(test_memoized_sensor); + RUN_TEST(test_calibrated_sensor); return UNITY_END(); } From 936a2638412bb17991bbf8cd581986d712f4bae0 Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Mon, 12 Jun 2023 23:01:30 +0400 Subject: [PATCH 15/16] feat(OpenGloves): add gestures --- .../mode_configs/opengloves/opengloves.cpp | 34 ++++++- lib/opengloves/sensor/og_finger.hpp | 9 +- lib/opengloves/sensor/og_gesture.hpp | 86 ++++++++++++++++ test/test_opengloves_gesture/main.cpp | 98 +++++++++++++++++++ 4 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 lib/opengloves/sensor/og_gesture.hpp create mode 100644 test/test_opengloves_gesture/main.cpp diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp index 7827947d..235129f5 100644 --- a/firmware/mode_configs/opengloves/opengloves.cpp +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #ifndef CALIBRATION_CURL @@ -34,6 +35,20 @@ #define BUTTON_COUNT (BUTTON_A_ENABLED + BUTTON_B_ENABLED + BUTTON_MENU_ENABLED + BUTTON_JOYSTICK_ENABLED + BUTTON_CALIBRATE_ENABLED + BUTTON_TRIGGER_ENABLED + BUTTON_GRAB_ENABLED + BUTTON_PINCH_ENABLED) #define BUTTON_CLASS(type, pin, invert) new StringEncodedMemoizedSensor(new OH::DigitalSensor(pin), type) +#ifndef GESTURE_TRIGGER_THRESHOLD +#define GESTURE_TRIGGER_THRESHOLD (ANALOG_MAX / 2) +#endif + +#ifndef GESTURE_GRAB_THRESHOLD +#define GESTURE_GRAB_THRESHOLD (ANALOG_MAX / 2) +#endif + +#ifndef GESTURE_PINCH_THRESHOLD +#define GESTURE_PINCH_THRESHOLD (ANALOG_MAX / 2) +#endif + +#define GESTURE_CLASS(type, sensor) new StringEncodedMemoizedSensor(sensor, type) + #ifndef UPDATE_RATE #define UPDATE_RATE 90 #endif @@ -98,25 +113,38 @@ std::vector*> buttons = std::vector, public virtual OH::ICalibrated { + class ICurl { + public : + virtual uint16_t getCurl() = 0; + }; + + class IFinger : public StringEncodedMemoizedSensor, public virtual OH::ICalibrated, public virtual ICurl { public : IFinger(OH::CalibratedSensor* sensor, IEncodedInput::Type type) : StringEncodedMemoizedSensor(sensor, type) { }; - uint16_t getCurl() { + uint16_t getCurl() override { return this->getValue(); } }; diff --git a/lib/opengloves/sensor/og_gesture.hpp b/lib/opengloves/sensor/og_gesture.hpp new file mode 100644 index 00000000..464c31f8 --- /dev/null +++ b/lib/opengloves/sensor/og_gesture.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include + +namespace OpenGloves +{ + class Gesture : public OH::ISensor { + + }; + + class GrabGesture : public Gesture { + private: + ICurl* index; + ICurl* middle; + ICurl* ring; + ICurl* pinky; + uint16_t threshold; + + public: + GrabGesture( + ICurl* index, + ICurl* middle, + ICurl* ring, + ICurl* pinky, + uint16_t threshold + ) : index(index), middle(middle), ring(ring), pinky(pinky), threshold(threshold) { }; + + void setup() override { + // this->index->setup(); + // this->middle->setup(); + // this->ring->setup(); + // this->pinky->setup(); + }; + + bool getValue() override { + return this->index->getCurl() > this->threshold + && this->middle->getCurl() > this->threshold + && this->ring->getCurl() > this->threshold + && this->pinky->getCurl() > this->threshold; + } + }; + + class TriggerGesture : public Gesture { + private: + ICurl* index; + uint16_t threshold; + + public: + TriggerGesture( + ICurl* index, + uint16_t threshold + ) : index(index), threshold(threshold) { }; + + void setup() override { + // this->index->setup(); + }; + + bool getValue() override { + return this->index->getCurl() > this->threshold; + } + }; + + class PinchGesture : public Gesture { + private: + ICurl* index; + ICurl* thumb; + uint16_t threshold; + + public: + PinchGesture( + ICurl* index, + ICurl* thumb, + uint16_t threshold + ) : index(index), thumb(thumb), threshold(threshold) { }; + + void setup() override { + // this->index->setup(); + // this->thumb->setup(); + }; + + bool getValue() override { + return this->index->getCurl() > this->threshold + && this->thumb->getCurl() > this->threshold; + } + }; +} // namespace OpenGloves diff --git a/test/test_opengloves_gesture/main.cpp b/test/test_opengloves_gesture/main.cpp new file mode 100644 index 00000000..11d9e112 --- /dev/null +++ b/test/test_opengloves_gesture/main.cpp @@ -0,0 +1,98 @@ +#include +#include + +using namespace OpenGloves; + +class TestCurlFinger : public ICurl { + public: + uint16_t value; + + TestCurlFinger(uint16_t initialValue = 0) : value(initialValue) { }; + + uint16_t getCurl() override { + return this->value; + } +}; + +void test_gesture_grab(void) { + uint16_t threshold = 2047; + + auto* index = new TestCurlFinger(threshold - 1); + auto* middle = new TestCurlFinger(threshold - 1); + auto* ring = new TestCurlFinger(threshold - 1); + auto* pinky = new TestCurlFinger(threshold - 1); + + auto* gesture = new GrabGesture(index, middle, ring, pinky, threshold); + + TEST_ASSERT_FALSE(gesture->getValue()); + + index->value = threshold + 1; + TEST_ASSERT_FALSE(gesture->getValue()); + + middle->value = threshold + 1; + TEST_ASSERT_FALSE(gesture->getValue()); + + ring->value = threshold + 1; + TEST_ASSERT_FALSE(gesture->getValue()); + + pinky->value = threshold + 1; + TEST_ASSERT_TRUE(gesture->getValue()); +} + +void test_gesture_trigger(void) { + uint16_t threshold = 2047; + + auto* index = new TestCurlFinger(threshold - 1); + + auto* gesture = new TriggerGesture(index, threshold); + + TEST_ASSERT_FALSE(gesture->getValue()); + + index->value = threshold + 1; + TEST_ASSERT_TRUE(gesture->getValue()); +} + +void test_gesture_pinch(void) { + uint16_t threshold = 2047; + + auto* index = new TestCurlFinger(threshold - 1); + auto* middle = new TestCurlFinger(threshold - 1); + + auto* gesture = new PinchGesture(index, middle, threshold); + + TEST_ASSERT_FALSE(gesture->getValue()); + + index->value = threshold + 1; + TEST_ASSERT_FALSE(gesture->getValue()); + + middle->value = threshold + 1; + TEST_ASSERT_TRUE(gesture->getValue()); +} + +int process(void) { + UNITY_BEGIN(); + + RUN_TEST(test_gesture_grab); + RUN_TEST(test_gesture_trigger); + RUN_TEST(test_gesture_pinch); + + return UNITY_END(); +} + +#ifdef ARDUINO + +#include + +void setup(void) { + process(); +} + +void loop(void) {} + +#else + +int main(int argc, char** argv) { + return process(); +} + +#endif From 3ccc213241567553a9692fdc56bd77d8cedaa943 Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Tue, 13 Jun 2023 11:20:16 +0400 Subject: [PATCH 16/16] feat(OpenGloves): enable calibration on button press --- .../mode_configs/opengloves/opengloves.cpp | 57 +++++++++++++++++-- ini/opengloves.ini | 9 +-- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/firmware/mode_configs/opengloves/opengloves.cpp b/firmware/mode_configs/opengloves/opengloves.cpp index 235129f5..bfa4b8b5 100644 --- a/firmware/mode_configs/opengloves/opengloves.cpp +++ b/firmware/mode_configs/opengloves/opengloves.cpp @@ -8,9 +8,18 @@ #include #include +#pragma region Calibration + #ifndef CALIBRATION_CURL #define CALIBRATION_CURL OH::MinMaxCalibrator #endif +#ifndef CALIBRATION_DURATION +#define CALIBRATION_DURATION 2000 // duration in milliseconds +#endif + +#pragma endregion + +#pragma region Fingers #define FINGER_THUMB_ENABLED (PIN_FINGER_THUMB != -1) #define FINGER_INDEX_ENABLED (PIN_FINGER_INDEX != -1) @@ -20,10 +29,18 @@ #define FINGER_COUNT (FINGER_THUMB_ENABLED + FINGER_INDEX_ENABLED + FINGER_MIDDLE_ENABLED + FINGER_RING_ENABLED + FINGER_PINKY_ENABLED) #define FINGER_CLASS(type, pin, invert, calib) new FingerSensor(new OH::CalibratedSensor(new OH::AnalogSensor(pin), new calib()), type) +#pragma endregion + +#pragma region Joysticks + #define JOYSTICK_ENABLED (PIN_JOYSTICK_X != -1 && PIN_JOYSTICK_Y != -1) #define JOYSTICK_COUNT (JOYSTICK_ENABLED ? 2 : 0) #define JOYSTICK_CLASS(type, pin, invert, deadzone) new StringEncodedMemoizedSensor(new OH::JoystickAxisSensor(new OH::AnalogSensor(pin), deadzone), type) +#pragma endregion + +#pragma region Buttons + #define BUTTON_A_ENABLED (PIN_BUTTON_A != -1) #define BUTTON_B_ENABLED (PIN_BUTTON_B != -1) #define BUTTON_MENU_ENABLED (PIN_BUTTON_MENU != -1) @@ -35,6 +52,10 @@ #define BUTTON_COUNT (BUTTON_A_ENABLED + BUTTON_B_ENABLED + BUTTON_MENU_ENABLED + BUTTON_JOYSTICK_ENABLED + BUTTON_CALIBRATE_ENABLED + BUTTON_TRIGGER_ENABLED + BUTTON_GRAB_ENABLED + BUTTON_PINCH_ENABLED) #define BUTTON_CLASS(type, pin, invert) new StringEncodedMemoizedSensor(new OH::DigitalSensor(pin), type) +#pragma endregion + +#pragma region Gestures + #ifndef GESTURE_TRIGGER_THRESHOLD #define GESTURE_TRIGGER_THRESHOLD (ANALOG_MAX / 2) #endif @@ -49,6 +70,8 @@ #define GESTURE_CLASS(type, sensor) new StringEncodedMemoizedSensor(sensor, type) +#pragma endregion + #ifndef UPDATE_RATE #define UPDATE_RATE 90 #endif @@ -150,7 +173,17 @@ std::vector*> buttons = std::vector inputs = std::vector(); + std::vector calibrated = std::vector(); +unsigned long long calibrationStarted = 0; +void startCalibration(void) { + for (size_t i = 0; i < calibrated.size(); i++) { + auto* input = calibrated[i]; + input->resetCalibration(); + input->enableCalibration(); + } + calibrationStarted = millis(); +} auto communication = new SerialCommunication(&Serial); @@ -159,10 +192,6 @@ void setupMode() { auto* finger = fingers[i]; finger->setup(); - #if defined(CALIBRATION_ALWAYS_CALIBRATE) && CALIBRATION_ALWAYS_CALIBRATE - finger->enableCalibration(); - #endif - inputs.push_back(finger); calibrated.push_back(finger); } @@ -181,6 +210,10 @@ void setupMode() { inputs.push_back(button); } +#if defined(CALIBRATION_ALWAYS_CALIBRATE) && CALIBRATION_ALWAYS_CALIBRATE + startCalibration(); +#endif + communication->setup(); } @@ -193,6 +226,22 @@ void loopMode() { input->updateValue(); } +#if BUTTON_CALIBRATE_ENABLED + if (calibrateButton->getValue() == true) { + startCalibration(); + } +#endif + +#if !CALIBRATION_ALWAYS_CALIBRATE + if (calibrationStarted > 0 && now - calibrationStarted > CALIBRATION_DURATION) { + for (size_t i = 0; i < calibrated.size(); i++) { + auto* input = calibrated[i]; + input->disableCalibration(); + } + calibrationStarted = 0; + } +#endif + // send all sensor values communication->send(inputs); diff --git a/ini/opengloves.ini b/ini/opengloves.ini index 9f22e627..e7b6a687 100644 --- a/ini/opengloves.ini +++ b/ini/opengloves.ini @@ -32,11 +32,8 @@ build_flags = ${common.build_flags} -D GESTURE_GRAB_ENABLED=true -D GESTURE_PINCH_ENABLED=true - ; Calibration - -D CALIBRATION_ALWAYS_CALIBRATE=false - ; Pins configuration - ; If pin set to -1, then it will be ignored + ; If pin set to -1, then it will be disabled -D PIN_FINGER_THUMB=32 -D PIN_FINGER_INDEX=35 -D PIN_FINGER_MIDDLE=34 @@ -55,6 +52,10 @@ build_flags = ${common.build_flags} -D PIN_BUTTON_GRAB=13 ; unused if GESTURE_GRAB is true -D PIN_BUTTON_PINCH=23 ; unused if GESTURE_PINCH is true + ; Calibration + -D CALIBRATION_ALWAYS_CALIBRATE=false + -D CALIBRATION_DURATION=2000 ; in ms + -D UPDATE_RATE=90 ; sensors update rate in Hz build_unflags = ${common.build_unflags}