├── .gitignore ├── hardware ├── Prototype3 │ ├── Prot3_Cover.STL │ ├── Prot3_EndCap.STL │ ├── Prot3_Holder.STL │ ├── Prot3_Spool.STL │ ├── Prot3_GuideRing.STL │ └── Prot3_Tensioner.STL ├── Prototype4 │ ├── HapticSpool.STL │ ├── Prot4_EndCap.STL │ ├── SpoolCover_open.STL │ ├── Tensioner_WLPot.STL │ ├── WLPotSlideHolder.STL │ ├── GreenPotSlideHolder.STL │ ├── Quest2_MountSlider.STL │ ├── RigidMount_leftHand.STL │ ├── RigidMount_rightHand.STL │ ├── Tensioner_GreenPot.STL │ ├── WLPotElasticHolder.STL │ ├── GreenPotElasticHolder.stl │ └── Vive3.0_MountSlider_v1.STL ├── Prototype3.1 │ ├── Prot3_EndCap.STL │ ├── Prot3.1_Holder.stl │ ├── Prot3.1_GuideNode.STL │ ├── Prot3.1_Tensioner.STL │ ├── Prot3.1R2_EasySpool.STL │ ├── Prot3.1R2_SpoolCover.STL │ ├── Prot3.1R2_SpoolCover_Taller.STL │ ├── Prot3.1_Wirecover_PublicBeta.STL │ └── README.md ├── Prototype4.1 │ ├── GuideNode_upgraded.STL │ ├── HapticSpool_Proto4.1.STL │ ├── Vive3.0_MountSlider_v1.2.STL │ ├── WLPotSlideHolder_Proto4.1.STL │ ├── GreenPotSildeHolder_Proto4.1.STL │ ├── WLPotElasticHolder_Proto4.1.STL │ └── GreenPotElasticHolder_Proto4.1.STL ├── Prototype5_BETA │ ├── FingerRack_v5.2.STL │ ├── MountSpacer_V1.STL │ ├── SensorTop_v4.0.STL │ ├── ServoGear_v3.3.STL │ ├── ServoRack_v3.6.STL │ ├── MagnetPinion_v5.3.STL │ ├── BearingRetainer_v1.2.STL │ ├── RigidMount_Splay_v3.STL │ ├── RigidMount_Splay_v4.STL │ ├── SensorHousing_v5.9.STL │ ├── EndRings │ │ ├── EndRing_v1.2_13mm.STL │ │ ├── EndRing_v1.2_15mm.STL │ │ ├── EndRing_v1.2_16mm.STL │ │ └── EndRing_v1.2_18mm.STL │ └── GuideRings │ │ ├── GuideRing_v1.2_15mm.STL │ │ ├── GuideRing_v1.2_17mm.STL │ │ ├── GuideRing_v1.2_18mm.STL │ │ ├── GuideRing_v1.2_19mm.STL │ │ ├── GuideRing_v1.2_21mm.STL │ │ └── GuideRing_v1.2_22mm.STL ├── MicrocontrollerMounts │ └── ESP32_Wroom_Holder_Desoldered_JST.STL └── README.md ├── firmware └── lucidgloves-firmware │ ├── README.md │ ├── src │ ├── Controller │ │ ├── Gesture.h │ │ ├── Gesture.cpp │ │ ├── Haptics.h │ │ ├── Haptics.cpp │ │ ├── InputManager.h │ │ └── InputManager.cpp │ ├── Encoding │ │ ├── LegacyEncoding.h │ │ ├── IEncoding.h │ │ ├── AlphaEncoding.h │ │ ├── LegacyEncoding.cpp │ │ └── AlphaEncoding.cpp │ ├── Communication │ │ ├── ICommunication.h │ │ ├── SerialCommunication.h │ │ ├── BTSerialCommunication.h │ │ ├── WIFISerialCommunication.h │ │ ├── SerialCommunication.cpp │ │ ├── BTSerialCommunication.cpp │ │ └── WIFISerialCommunication.cpp │ ├── Main.h │ ├── Util │ │ ├── DataStructs.h │ │ └── ConfigUtils.h │ └── Main.cpp │ ├── lucidgloves-firmware.ino │ ├── AdvancedConfig.h │ └── Config.h ├── LICENSE ├── Readme_Languages └── README_CN.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | firmware/lucidgloves-firmware/.vscode/* 3 | -------------------------------------------------------------------------------- /hardware/Prototype3/Prot3_Cover.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3/Prot3_Cover.STL -------------------------------------------------------------------------------- /hardware/Prototype3/Prot3_EndCap.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3/Prot3_EndCap.STL -------------------------------------------------------------------------------- /hardware/Prototype3/Prot3_Holder.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3/Prot3_Holder.STL -------------------------------------------------------------------------------- /hardware/Prototype3/Prot3_Spool.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3/Prot3_Spool.STL -------------------------------------------------------------------------------- /hardware/Prototype4/HapticSpool.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/HapticSpool.STL -------------------------------------------------------------------------------- /hardware/Prototype4/Prot4_EndCap.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/Prot4_EndCap.STL -------------------------------------------------------------------------------- /hardware/Prototype3.1/Prot3_EndCap.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3.1/Prot3_EndCap.STL -------------------------------------------------------------------------------- /hardware/Prototype3/Prot3_GuideRing.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3/Prot3_GuideRing.STL -------------------------------------------------------------------------------- /hardware/Prototype3/Prot3_Tensioner.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3/Prot3_Tensioner.STL -------------------------------------------------------------------------------- /hardware/Prototype4/SpoolCover_open.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/SpoolCover_open.STL -------------------------------------------------------------------------------- /hardware/Prototype4/Tensioner_WLPot.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/Tensioner_WLPot.STL -------------------------------------------------------------------------------- /hardware/Prototype3.1/Prot3.1_Holder.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3.1/Prot3.1_Holder.stl -------------------------------------------------------------------------------- /hardware/Prototype4/WLPotSlideHolder.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/WLPotSlideHolder.STL -------------------------------------------------------------------------------- /hardware/Prototype3.1/Prot3.1_GuideNode.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3.1/Prot3.1_GuideNode.STL -------------------------------------------------------------------------------- /hardware/Prototype3.1/Prot3.1_Tensioner.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3.1/Prot3.1_Tensioner.STL -------------------------------------------------------------------------------- /hardware/Prototype4.1/GuideNode_upgraded.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4.1/GuideNode_upgraded.STL -------------------------------------------------------------------------------- /hardware/Prototype4/GreenPotSlideHolder.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/GreenPotSlideHolder.STL -------------------------------------------------------------------------------- /hardware/Prototype4/Quest2_MountSlider.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/Quest2_MountSlider.STL -------------------------------------------------------------------------------- /hardware/Prototype4/RigidMount_leftHand.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/RigidMount_leftHand.STL -------------------------------------------------------------------------------- /hardware/Prototype4/RigidMount_rightHand.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/RigidMount_rightHand.STL -------------------------------------------------------------------------------- /hardware/Prototype4/Tensioner_GreenPot.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/Tensioner_GreenPot.STL -------------------------------------------------------------------------------- /hardware/Prototype4/WLPotElasticHolder.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/WLPotElasticHolder.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/FingerRack_v5.2.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/FingerRack_v5.2.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/MountSpacer_V1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/MountSpacer_V1.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/SensorTop_v4.0.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/SensorTop_v4.0.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/ServoGear_v3.3.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/ServoGear_v3.3.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/ServoRack_v3.6.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/ServoRack_v3.6.STL -------------------------------------------------------------------------------- /hardware/Prototype3.1/Prot3.1R2_EasySpool.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3.1/Prot3.1R2_EasySpool.STL -------------------------------------------------------------------------------- /hardware/Prototype3.1/Prot3.1R2_SpoolCover.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3.1/Prot3.1R2_SpoolCover.STL -------------------------------------------------------------------------------- /hardware/Prototype4.1/HapticSpool_Proto4.1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4.1/HapticSpool_Proto4.1.STL -------------------------------------------------------------------------------- /hardware/Prototype4/GreenPotElasticHolder.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/GreenPotElasticHolder.stl -------------------------------------------------------------------------------- /hardware/Prototype4/Vive3.0_MountSlider_v1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4/Vive3.0_MountSlider_v1.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/MagnetPinion_v5.3.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/MagnetPinion_v5.3.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/BearingRetainer_v1.2.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/BearingRetainer_v1.2.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/RigidMount_Splay_v3.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/RigidMount_Splay_v3.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/RigidMount_Splay_v4.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/RigidMount_Splay_v4.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/SensorHousing_v5.9.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/SensorHousing_v5.9.STL -------------------------------------------------------------------------------- /hardware/Prototype4.1/Vive3.0_MountSlider_v1.2.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4.1/Vive3.0_MountSlider_v1.2.STL -------------------------------------------------------------------------------- /hardware/Prototype4.1/WLPotSlideHolder_Proto4.1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4.1/WLPotSlideHolder_Proto4.1.STL -------------------------------------------------------------------------------- /hardware/Prototype3.1/Prot3.1R2_SpoolCover_Taller.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3.1/Prot3.1R2_SpoolCover_Taller.STL -------------------------------------------------------------------------------- /hardware/Prototype3.1/Prot3.1_Wirecover_PublicBeta.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype3.1/Prot3.1_Wirecover_PublicBeta.STL -------------------------------------------------------------------------------- /hardware/Prototype4.1/GreenPotSildeHolder_Proto4.1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4.1/GreenPotSildeHolder_Proto4.1.STL -------------------------------------------------------------------------------- /hardware/Prototype4.1/WLPotElasticHolder_Proto4.1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4.1/WLPotElasticHolder_Proto4.1.STL -------------------------------------------------------------------------------- /hardware/Prototype4.1/GreenPotElasticHolder_Proto4.1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype4.1/GreenPotElasticHolder_Proto4.1.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/EndRings/EndRing_v1.2_13mm.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/EndRings/EndRing_v1.2_13mm.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/EndRings/EndRing_v1.2_15mm.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/EndRings/EndRing_v1.2_15mm.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/EndRings/EndRing_v1.2_16mm.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/EndRings/EndRing_v1.2_16mm.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/EndRings/EndRing_v1.2_18mm.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/EndRings/EndRing_v1.2_18mm.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_15mm.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_15mm.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_17mm.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_17mm.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_18mm.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_18mm.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_19mm.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_19mm.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_21mm.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_21mm.STL -------------------------------------------------------------------------------- /hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_22mm.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/Prototype5_BETA/GuideRings/GuideRing_v1.2_22mm.STL -------------------------------------------------------------------------------- /hardware/MicrocontrollerMounts/ESP32_Wroom_Holder_Desoldered_JST.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucidVR/lucidgloves/HEAD/hardware/MicrocontrollerMounts/ESP32_Wroom_Holder_Desoldered_JST.STL -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/README.md: -------------------------------------------------------------------------------- 1 | # lucidgloves-firmware 2 | 3 | 4 | Check the [Wiki](https://github.com/LucidVR/lucidgloves/wiki/Firmware-Setup-and-Customization-Tutorial/) for instructions on how to set it up. 5 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Controller/Gesture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../AdvancedConfig.h" 3 | 4 | class Gesture { 5 | public: 6 | bool grabGesture(int *flexion); 7 | bool pinchGesture(int *flexion); 8 | bool triggerGesture(int *flexion); 9 | }; 10 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Encoding/LegacyEncoding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IEncoding.h" 4 | #include "Config.h" 5 | 6 | class LegacyEncoding : public IEncoding { 7 | public: 8 | void encode(OutboundData data, char* stringToEncode) override; 9 | DecodedData decodeData(char* stringToDecode) override; 10 | }; 11 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Encoding/IEncoding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Util/DataStructs.h" 3 | 4 | 5 | 6 | 7 | // Interface for encoding 8 | class IEncoding { 9 | public: 10 | virtual void encode(OutboundData data, char* stringToEncode) = 0; 11 | 12 | virtual DecodedData decodeData(char* stringToDecode) = 0; 13 | }; 14 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Communication/ICommunication.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //Interface for communication 4 | class ICommunication { 5 | 6 | public: 7 | virtual bool isOpen() = 0; 8 | 9 | virtual void start() = 0; 10 | 11 | virtual void output(char* data) = 0; 12 | 13 | virtual bool readData(char* input) = 0; 14 | }; 15 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Encoding/AlphaEncoding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IEncoding.h" 4 | #include "Config.h" 5 | 6 | class AlphaEncoding : public IEncoding { 7 | public: 8 | void encode(OutboundData data, char* stringToEncode) override; 9 | DecodedData decodeData(char* stringToDecode) override; 10 | private: 11 | int getArgument(char* stringToDecode, char command); 12 | }; 13 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Communication/SerialCommunication.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ICommunication.h" 3 | #include "../../Config.h" 4 | #include 5 | 6 | class SerialCommunication : public ICommunication { 7 | private: 8 | bool m_isOpen; 9 | 10 | public: 11 | SerialCommunication(); 12 | 13 | bool isOpen() override; 14 | 15 | void start() override; 16 | 17 | void output(char* data) override; 18 | 19 | bool readData(char* input) override; 20 | }; 21 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Controller/Gesture.cpp: -------------------------------------------------------------------------------- 1 | #include "Gesture.h" 2 | 3 | bool Gesture::grabGesture(int *flexion){ 4 | return (flexion[PINKY_IND] + flexion[RING_IND] + flexion[MIDDLE_IND] + flexion[INDEX_IND]) / 4 <= ANALOG_MAX/2 ? 0:1; 5 | } 6 | 7 | bool Gesture::pinchGesture(int *flexion){ 8 | return (flexion[INDEX_IND] + flexion[THUMB_IND]) / 2 <= ANALOG_MAX/2 ? 0:1; 9 | } 10 | 11 | bool Gesture::triggerGesture(int *flexion){ 12 | return flexion[INDEX_IND]<=(ANALOG_MAX/2)?0:1; 13 | } 14 | -------------------------------------------------------------------------------- /hardware/README.md: -------------------------------------------------------------------------------- 1 | # lucidgloves-hardware 2 | 3 | 4 | Here are the 3D models for your printed glove parts. 5 | The x.1 versions have slight tweaks over their counterparts to make them more easily printable and durable, so prefer those when available. 6 | If you are on the fence between having haptics or not, you can print the Prototype v4 without servos and add them later. 7 | 8 | Check the [printing guides](https://github.com/LucidVR/lucidgloves/wiki/Parts-Printing-Guide) to know how many you need to print and how. 9 | -------------------------------------------------------------------------------- /hardware/Prototype3.1/README.md: -------------------------------------------------------------------------------- 1 | # LucidGloves Hardware Prototype 3.1 2 | 3 | See [readme.md](readme.md) for the master readme of this repository. 4 | 5 | This folder contains the STl files for Prototype 3.1 of the LucidGloves. 6 | Please see [Printing guide](https://github.com/LucidVR/lucidgloves-hardware/wiki/Parts-Printing-Guide) for printing instructions. 7 | 8 | Here is a list of modified versions of Prototype 3.1: 9 | * Feel free to pull request a repo link to your modded version. 10 | - Should follow the structure of "Mod name - mod creator - link to mod" 11 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/lucidgloves-firmware.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * LucidGloves Firmware Version 4 3 | * Author: Lucas_VRTech - LucidVR 4 | * lucidvrtech.com 5 | */ 6 | 7 | 8 | #include "src/Main.h" 9 | 10 | /* 11 | * 12 | * THE CONFIG SETTINGS ARE NO LONGER STORED HERE. THEY HAVE BEEN MOVED TO Config.h 13 | * 14 | * You can now change the settings over at config.h before uploading to your gloves. 15 | * 16 | */ 17 | 18 | 19 | Main mainClass; 20 | 21 | void setup(){ 22 | mainClass.setup(); 23 | } 24 | 25 | void loop(){ 26 | mainClass.loop(); 27 | } 28 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Communication/BTSerialCommunication.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ICommunication.h" 3 | #include "../../Config.h" 4 | 5 | #if COMMUNICATION == COMM_BTSERIAL 6 | #include "BluetoothSerial.h" 7 | 8 | class BTSerialCommunication : public ICommunication { 9 | private: 10 | bool m_isOpen; 11 | BluetoothSerial m_SerialBT; 12 | 13 | public: 14 | BTSerialCommunication(); 15 | 16 | bool isOpen() override; 17 | 18 | void start() override; 19 | 20 | void output(char* data) override; 21 | 22 | bool readData(char* input) override; 23 | }; 24 | #endif 25 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Controller/Haptics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../Config.h" 3 | 4 | #if defined(ESP32) 5 | #include "ESP32Servo.h" 6 | #else 7 | #include "Servo.h" 8 | #endif 9 | 10 | class Haptics { 11 | private: 12 | Servo pinkyServo; 13 | Servo ringServo; 14 | Servo middleServo; 15 | Servo indexServo; 16 | Servo thumbServo; 17 | 18 | public: 19 | void setupServoHaptics(); 20 | void scaleLimits(int* hapticLimits, float* scaledLimits); 21 | void dynScaleLimits(int* hapticLimits, float* scaledLimits); 22 | void writeServoHaptics(int* hapticLimits); 23 | }; 24 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Communication/WIFISerialCommunication.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ICommunication.h" 3 | #include "../../Config.h" 4 | 5 | #if COMMUNICATION == COMM_WIFISERIAL 6 | #include 7 | #include 8 | 9 | class WIFISerialCommunication : public ICommunication { 10 | private: 11 | bool m_isOpen; 12 | WiFiClient client; 13 | 14 | void connect(); 15 | 16 | public: 17 | WIFISerialCommunication(); 18 | 19 | bool isOpen() override; 20 | 21 | void start() override; 22 | 23 | void output(char *data) override; 24 | 25 | bool readData(char *input) override; 26 | }; 27 | #endif -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Communication/SerialCommunication.cpp: -------------------------------------------------------------------------------- 1 | #include "SerialCommunication.h" 2 | 3 | SerialCommunication::SerialCommunication() { 4 | m_isOpen = false; 5 | } 6 | 7 | bool SerialCommunication::isOpen() { 8 | return m_isOpen; 9 | } 10 | 11 | void SerialCommunication::start() { 12 | //Serial.setTimeout(1000000); 13 | Serial.begin(SERIAL_BAUD_RATE); 14 | m_isOpen = true; 15 | } 16 | 17 | void SerialCommunication::output(char* data) { 18 | Serial.print(data); 19 | Serial.flush(); 20 | } 21 | 22 | bool SerialCommunication::readData(char* input) { 23 | byte size = Serial.readBytesUntil('\n', input, 100); 24 | input[size] = NULL; 25 | return input != NULL && strlen(input) > 0; 26 | } 27 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Encoding/LegacyEncoding.cpp: -------------------------------------------------------------------------------- 1 | #include "LegacyEncoding.h" 2 | #include 3 | void LegacyEncoding::encode(OutboundData data, char* stringToEncode){ 4 | sprintf(stringToEncode, "%d&%d&%d&%d&%d&%d&%d&%d&%d&%d&%d&%d&%d\n", 5 | data.fingers[0], data.fingers[1], data.fingers[2], data.fingers[3], data.fingers[4], 6 | data.joyX, data.joyY, data.joyClick, 7 | data.triggerButton, data.aButton, data.bButton, data.grab, data.pinch 8 | ); 9 | } 10 | 11 | DecodedData LegacyEncoding::decodeData(char* stringToDecode) { 12 | DecodedData decodedData = {}; 13 | 14 | byte index = 0; 15 | char* ptr = strtok(stringToDecode, "&"); 16 | while(ptr != NULL && index < NUM_FINGERS) 17 | { 18 | decodedData.servoValues[index] = atoi(ptr); 19 | decodedData.fields.servoValuesReceived[index] = true; 20 | index++; 21 | ptr = strtok(NULL, "&"); 22 | } 23 | 24 | return decodedData; 25 | } 26 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Controller/Gesture.h" 5 | #include "Controller/Haptics.h" 6 | #include "../AdvancedConfig.h" 7 | #include "Communication/ICommunication.h" 8 | #include "Encoding/IEncoding.h" 9 | #include "Util/ConfigUtils.h" 10 | #include "Controller/InputManager.h" 11 | 12 | 13 | class Main { 14 | public: 15 | Main(); 16 | void setup(); 17 | void loop(); 18 | 19 | #if defined(ESP32_DUAL_CORE_SET) 20 | static void getInputsWrapper(void* _this); 21 | #endif 22 | 23 | private: 24 | 25 | ICommunication* comm; 26 | IEncoding* encoding; 27 | Haptics haptics; 28 | Gesture gesture; 29 | InputManager input; 30 | 31 | OutboundData data = {}; 32 | 33 | bool calibrate = false; 34 | int fingerPos[10] = {0,0,0,0,0,0,0,0,0,0}; 35 | int loops = 0; 36 | 37 | #if defined(ESP32_DUAL_CORE_SET) 38 | void getInputs(); 39 | ordered_lock* fingerPosLock = new ordered_lock(); 40 | TaskHandle_t Task1; 41 | int threadLoops = 1; 42 | #endif 43 | 44 | }; 45 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Util/DataStructs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../AdvancedConfig.h" 3 | 4 | const char* const SPECIAL_COMMANDS[] = { 5 | "SaveInter", 6 | "SaveTravel", 7 | "ClearData" 8 | // Add more commands as needed 9 | }; 10 | 11 | //NUM_SPECIAL_COMMANDS can be defined this way because all char* are pointers of the same size 12 | const int NUM_SPECIAL_COMMANDS = sizeof(SPECIAL_COMMANDS) / sizeof(SPECIAL_COMMANDS[0]); 13 | 14 | struct ReceivedFields { 15 | bool servoValuesReceived[NUM_FINGERS]; 16 | bool specialCommandReceived; 17 | }; 18 | 19 | struct DecodedData { 20 | ReceivedFields fields; 21 | int servoValues[NUM_FINGERS]; 22 | const char* command; 23 | }; 24 | 25 | struct OutboundData { 26 | int fingers[NUM_FINGERS]; 27 | int joyX; 28 | int joyY; 29 | bool joyClick; 30 | bool triggerButton; 31 | bool aButton; 32 | bool bButton; 33 | bool grab; 34 | bool pinch; 35 | bool calib; 36 | bool menu; 37 | 38 | #if USING_SPLAY 39 | int splay[NUM_FINGERS]; 40 | #endif 41 | }; -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Communication/BTSerialCommunication.cpp: -------------------------------------------------------------------------------- 1 | #include "BTSerialCommunication.h" 2 | 3 | #if COMMUNICATION == COMM_BTSERIAL 4 | 5 | BTSerialCommunication::BTSerialCommunication() { 6 | m_isOpen = false; 7 | } 8 | 9 | bool BTSerialCommunication::isOpen() { 10 | return m_isOpen; 11 | } 12 | 13 | void BTSerialCommunication::start() { 14 | m_SerialBT.begin(BTSERIAL_DEVICE_NAME); 15 | #if BT_ECHO 16 | Serial.begin(SERIAL_BAUD_RATE); 17 | Serial.println("The device started, now you can pair it with bluetooth!"); 18 | #endif 19 | m_isOpen = true; 20 | } 21 | 22 | void BTSerialCommunication::output(char* data) { 23 | m_SerialBT.print(data); 24 | #if BT_ECHO 25 | Serial.print(data); 26 | Serial.flush(); 27 | #endif 28 | } 29 | 30 | bool BTSerialCommunication::readData(char* input) { 31 | /*byte size = m_SerialBT.readBytesUntil('\n', input, 100); 32 | input[size] = NULL;*/ 33 | String message = m_SerialBT.readStringUntil('\n'); 34 | strcpy(input, message.c_str()); 35 | return input != NULL && strlen(input) > 0; 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 LucidVR 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Controller/Haptics.cpp: -------------------------------------------------------------------------------- 1 | #include "Haptics.h" 2 | 3 | #if USING_FORCE_FEEDBACK 4 | 5 | void Haptics::setupServoHaptics() { 6 | pinkyServo.attach(PIN_PINKY_MOTOR); 7 | ringServo.attach(PIN_RING_MOTOR); 8 | middleServo.attach(PIN_MIDDLE_MOTOR); 9 | indexServo.attach(PIN_INDEX_MOTOR); 10 | thumbServo.attach(PIN_THUMB_MOTOR); 11 | } 12 | 13 | void Haptics::scaleLimits(int* hapticLimits, float* scaledLimits) { 14 | for (int i = 0; i < 5; i++) { 15 | #if FLIP_FORCE_FEEDBACK 16 | scaledLimits[i] = hapticLimits[i] / 1000.0f * 180.0f; 17 | #else 18 | scaledLimits[i] = 180.0f - hapticLimits[i] / 1000.0f * 180.0f; 19 | #endif 20 | } 21 | } 22 | 23 | void Haptics::dynScaleLimits(int* hapticLimits, float* scaledLimits) { 24 | for (int i = 0; i < sizeof(hapticLimits); i++) { 25 | scaledLimits[i] = hapticLimits[i] / 1000.0f * 180.0f; 26 | } 27 | } 28 | 29 | void Haptics::writeServoHaptics(int* hapticLimits) { 30 | float scaledLimits[5]; 31 | scaleLimits(hapticLimits, scaledLimits); 32 | if (hapticLimits[0] >= 0) thumbServo.write(scaledLimits[0]); 33 | if (hapticLimits[1] >= 0) indexServo.write(scaledLimits[1]); 34 | if (hapticLimits[2] >= 0) middleServo.write(scaledLimits[2]); 35 | if (hapticLimits[3] >= 0) ringServo.write(scaledLimits[3]); 36 | if (hapticLimits[4] >= 0) pinkyServo.write(scaledLimits[4]); 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Util/ConfigUtils.h: -------------------------------------------------------------------------------- 1 | //Contains the definitions that need to be evaluated before the main config file (Config.h). 2 | //These shouldn't need to be changed. 3 | 4 | #pragma once 5 | #ifndef CONFIGUTILS_H 6 | #define CONFIGUTILS_H 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | class ordered_lock { 13 | std::queue cvar; 14 | std::mutex cvar_lock; 15 | bool locked; 16 | public: 17 | ordered_lock() : locked(false) {}; 18 | void lock() { 19 | std::unique_lock acquire(cvar_lock); 20 | if (locked) { 21 | std::condition_variable signal; 22 | cvar.emplace(&signal); 23 | signal.wait(acquire); 24 | } else { 25 | locked = true; 26 | } 27 | } 28 | void unlock() { 29 | std::unique_lock acquire(cvar_lock); 30 | if (cvar.empty()) { 31 | locked = false; 32 | } else { 33 | cvar.front()->notify_one(); 34 | cvar.pop(); 35 | } 36 | } 37 | }; 38 | 39 | //Comm 40 | #define COMM_SERIAL 0 41 | #define COMM_BTSERIAL 1 42 | #define COMM_WIFISERIAL 2 43 | 44 | //Encode 45 | #define ENCODE_LEGACY 0 46 | #define ENCODE_ALPHA 1 47 | 48 | //Multiplexer 49 | #define MUX(p) (p + 100) 50 | #define UNMUX(p) (p % 100) 51 | #define ISMUX(p) (p >= 100) 52 | 53 | //finger mixing 54 | #define MIXING_NONE 0 55 | #define MIXING_SINCOS 2 56 | 57 | //intermediate filtering 58 | #define INTERFILTER_NONE 0 59 | #define INTERFILTER_LIMITS 1 60 | #define INTERFILTER_ALL 2 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Communication/WIFISerialCommunication.cpp: -------------------------------------------------------------------------------- 1 | #include "WIFISerialCommunication.h" 2 | // only compiles if WIFISerial is set because it won't compile for a non-compatible board 3 | #if COMMUNICATION == COMM_WIFISERIAL 4 | 5 | void WIFISerialCommunication::connect() 6 | { 7 | while (!client.connect(host, port)) // blocks thread until connected 8 | delay(500); 9 | Serial.print("Connected to Server at" + String(client.localIP()) + ":" + String(client.localPort())); 10 | } 11 | 12 | 13 | WIFISerialCommunication::WIFISerialCommunication() 14 | { 15 | m_isOpen = false; 16 | } 17 | 18 | bool WIFISerialCommunication::isOpen() 19 | { 20 | return m_isOpen; 21 | } 22 | 23 | void WIFISerialCommunication::start() 24 | { 25 | Serial.begin(SERIAL_BAUD_RATE); 26 | WiFi.begin(ssid, password); 27 | while (WiFi.status() != WL_CONNECTED) 28 | { 29 | delay(1000); 30 | Serial.println("Connecting to WiFi..."); 31 | } 32 | m_isOpen = true; 33 | Serial.println("Connected to WiFi"); 34 | 35 | connect(); 36 | } 37 | void WIFISerialCommunication::output(char *data) 38 | { 39 | if (!client.connected()) 40 | { 41 | Serial.println("Client not connected, attempting reconnect"); 42 | connect(); 43 | } 44 | client.println(data); 45 | } 46 | 47 | bool WIFISerialCommunication::readData(char *input) 48 | { 49 | if (!client.connected()) 50 | { 51 | Serial.println("Client not connected, attempting reconnect"); 52 | connect(); 53 | } 54 | String message = client.readStringUntil('\n'); 55 | // String message = client.readStringUntil('\n', input, 100); 56 | // input[size] = NULL; 57 | strcpy(input, message.c_str()); 58 | 59 | return input != NULL && strlen(input) > 0; 60 | } 61 | #endif -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Encoding/AlphaEncoding.cpp: -------------------------------------------------------------------------------- 1 | #include "AlphaEncoding.h" 2 | #include 3 | void AlphaEncoding::encode(OutboundData data, char* stringToEncode){ 4 | int trigger = (data.fingers[1] > ANALOG_MAX/2) ? (data.fingers[1] - ANALOG_MAX/2) * 2:0; 5 | char splayString[30] = ""; 6 | #if USING_SPLAY 7 | sprintf(splayString, "(AB)%d(BB)%d(CB)%d(DB)%d(EB)%d", 8 | data.splay[0], data.splay[1], data.splay[2], data.splay[3], data.splay[4] 9 | ); 10 | #endif 11 | snprintf(stringToEncode, 100, "A%dB%dC%dD%dE%dF%dG%dP%d%s%s%s%s%s%s%s%s%s\n", 12 | data.fingers[0], data.fingers[1], data.fingers[2], data.fingers[3], data.fingers[4], 13 | data.joyX, data.joyY, trigger, data.joyClick?"H":"", 14 | data.triggerButton?"I":"", data.aButton?"J":"", data.bButton?"K":"", data.grab?"L":"", data.pinch?"M":"", data.menu?"N":"", data.calib?"O":"", 15 | splayString); 16 | } 17 | DecodedData AlphaEncoding::decodeData(char* stringToDecode) { 18 | DecodedData decodedData = {}; 19 | 20 | if (strchr(stringToDecode, 'Z') != NULL) { 21 | for (int i = 0; i < NUM_SPECIAL_COMMANDS; i++) { 22 | if (strstr(stringToDecode, SPECIAL_COMMANDS[i]) != NULL) { 23 | decodedData.command = SPECIAL_COMMANDS[i]; 24 | decodedData.fields.specialCommandReceived = true; 25 | return decodedData; 26 | } 27 | } 28 | } 29 | 30 | for (int i = 0; i < NUM_FINGERS; i++) { 31 | int value = getArgument(stringToDecode, 'A' + i); 32 | if (value != -1) { 33 | decodedData.servoValues[i] = value; 34 | decodedData.fields.servoValuesReceived[i] = true; 35 | } 36 | } 37 | 38 | return decodedData; 39 | } 40 | 41 | 42 | int AlphaEncoding::getArgument(char* stringToDecode, char command){ 43 | char* start = strchr(stringToDecode, command); 44 | if (start == NULL) 45 | return -1; 46 | else 47 | return atoi(start + 1); 48 | } 49 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/AdvancedConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "src/Util/ConfigUtils.h" 3 | //THIS FILE HAS SOME EXTRA SETTINGS, MAIN SETTINGS ARE IN Config.h 4 | 5 | #define LOOP_TIME 1 //How much time between data sends (ms), set to 0 for a good time :) 6 | #define CALIBRATION_LOOPS -1//How many loops should be calibrated. Set to -1 to always be calibrated. 7 | 8 | //Encoding 9 | #define ENCODING ENCODE_ALPHA 10 | 11 | #define NUM_FINGERS 5 12 | 13 | //Bluetooth advaned settings 14 | #define BT_ECHO false//Should the bluetooth data be echoed over serial for debugging 15 | 16 | //ESP32 Specific Settings 17 | #define ESP32_DUAL_CORE false //Should inputs be handled on a separate core for communication for more accurate rotation counting 18 | 19 | //Finger indeces (not used for legacy) 20 | #define PINKY_IND 4 21 | #define RING_IND 3 22 | #define MIDDLE_IND 2 23 | #define INDEX_IND 1 24 | #define THUMB_IND 0 25 | 26 | //Automatically set ANALOG_MAX depending on the microcontroller 27 | #if defined(__AVR__) 28 | #define ANALOG_MAX 1023 29 | #elif defined(ESP32) 30 | #define ANALOG_MAX 4095 31 | #endif 32 | 33 | 34 | #define MULTIPLEXER_DELAY 5 //How many microseconds should be delayed between multiplexer reads 35 | 36 | 37 | //ANALOG_MAX OVERRIDE: 38 | //#define ANALOG_MAX 4095 //uncomment and set as needed 39 | 40 | #ifndef ANALOG_MAX 41 | #error "This board doesn't have an auto ANALOG_MAX assignment, please set it manually by uncommenting the line below ANALOG_MAX OVERRIDE in AdvancedConfig.h" 42 | #endif 43 | 44 | //Filtering and clamping analog inputs 45 | #define CLAMP_ANALOG_MAP true //clamp the mapped analog values from 0 to ANALOG_MAX 46 | 47 | // Enable and set min and max to match your sensor's expected raw value range 48 | // This discards any spurious values outside of the useful range 49 | #define CLAMP_SENSORS false //clamp the raw sensor values 50 | #define CLAMP_MIN 0 //the minimum value from the flexion sensors 51 | #define CLAMP_MAX ANALOG_MAX //the maximum value from the flexion sensors 52 | 53 | // You must install RunningMedian library to use this feature 54 | // https://www.arduino.cc/reference/en/libraries/runningmedian/ 55 | #define ENABLE_MEDIAN_FILTER false //use the median of the previous values, helps reduce noise 56 | #define MEDIAN_SAMPLES 10 57 | 58 | //intermediate filtering. Options are INTERFILTER_NONE, INTERFILTER_LIMITS (filter is only used for limit calib), INTERFILTER_ALL (filter all the way) 59 | #define INTERFILTER_MODE INTERFILTER_LIMITS 60 | #define INTERFILTER_SAMPLES 10 61 | 62 | //ESP dual core hardware check 63 | #if defined(ESP32) && ESP32_DUAL_CORE 64 | #define ESP32_DUAL_CORE_SET true 65 | #endif 66 | -------------------------------------------------------------------------------- /Readme_Languages/README_CN.md: -------------------------------------------------------------------------------- 1 | ![LucidGloves](https://cdn.discordapp.com/attachments/785135646082990120/873666310855360582/LucidGlovesBlackwbkgnd.png) 2 | 3 | # lucid手套- 固件与3D打印文件 4 | 此Repo含有lucid手套的原型机V3到V4的arduino固件以及3D打印所需要的STL文件。LucidGloves是DIY触觉反馈手指追踪手套,如果配合LucidVR使用,可以在大部分支持Valve Index手柄支持的游戏。我们的宗旨是用最少的钱,得到最大的体验。原作者Lucas_VRTech会在他的抖音账号里更新此项目的最新进展, 请关注https://www.tiktok.com/@lucas_vrtech 。 5 | 6 | # 支持此项目 7 | 欢迎计入LucidVR的discord服务器,更多详细问题以及内容可以在LucidVR的官方discord讨论: 8 | https://discord.gg/lucidvr 9 | 10 | # 固件 11 | 固件文件在firmware/lucidgloves-firmware文件夹. 12 | 此固件默认使用和配置arduino nano以及它的USB通讯端口。如果使用USB通讯端口,您需要使用相应的数据项与设备相连。 13 | 如果您想配置此固件,请在lucidgloves-firmware.ino文件做出相应的改变。 14 | 15 | **详细的配置方法:请点击此处进入配置教程 -> [配置教程传送门](https://github.com/LucidVR/lucidgloves-hardware/wiki/Firmware-V2-Customization).**\ 16 | **固件问题的故障排除教程:-> [固件故障排除教程](https://github.com/LucidVR/lucidgloves/wiki/Firmware-Troubleshooting-Guide).** 17 | 18 | ## 已测试过的主板: 19 | * Arduino Nano 20 | * ESP-WROOM-32 21 | 22 | ## 现已支持的通讯方法: 23 | * USB Serial 24 | * Bluetooth Serial (可以在 ESP32 boards实现,详情请看教程。) 25 | * BLE (敬请期待) 26 | 27 | # 硬件 28 | 3D打印所需要的STL文件在hardware文件夹。 29 | *关于原型机V4:目前还在测试阶段* 30 | 31 | 以下是针对**单个手套**需要打印以下材料: 32 | 33 | 原型机V3/V3.1: 34 | * Spool (5x) | 卷轴 35 | * Tensioner (5x) | 卷轴张紧器 36 | * Cover (5x) | 卷轴保护外圈 37 | * Holder (5x) | 卷轴固定器 38 | * GuideRing(Will need to be resized) OR GuideNode(3.1) (2+ per finger, 1+ for thumb) | 导环 39 | * EndCap (1x per finger, will need to be resized to fit) | 手指套 40 | 41 | 原型机V4/V4.1: 42 | * HapticSpool (5x) | 触觉反馈卷轴 43 | * Tensioner_GreenPot (5x) OR Tensioner_WLPot (5x) | 触觉反馈卷轴张紧器,根据您的电位器型号选择 44 | * SpoolCover (5x) | 卷轴保护外圈 45 | * RigidMount (2x) (One for each hand, make sure to flip for other hand) | 固定装置 46 | * WLPotSlideHolder OR WLPotElasticHolder OR GreenPotSlideHolder (5x) | 卷轴滑轨固定器 47 | * Quest2_MountSlider OR Vive3.0_MountSlider (2x) | Quest2手柄固定器 48 | * GuideRing (Proto 3) (Will need to be resized) OR GuideNode (Proto 3.1) (2+ per finger, 1+ for thumb) | 导环 49 | * EndCap (Proto 3) (1x per finger, will need to be resized to fit) | 手指套 50 | 51 | 52 | 3D打印教程: [打印教程传送门](https://github.com/LucidVR/lucidgloves-hardware/wiki/Parts-Printing-Guides) 53 | 54 | **需要购买的材料: [所需材料传送门](https://github.com/LucidVR/lucidgloves/wiki/Parts-Lists)** 55 | 可选配置: 56 | * 遥感:可以控制人物在游戏里的运动 57 | - 此项目的最终计划是加入VR跑步机 58 | * 按钮 (几乎所有按钮都可用手势替代) (至少需要一个来用作自动校准) 59 | 60 | 想要更多信息和情报?请关注[LucidVR官方网站](http://lucidvrtech.com/). 61 | * [原型机V3/V3.1制作教程](https://youtu.be/Qj4hqRKiy8g) 62 | * 原型机V4的教程会很快跟进的。 63 | 64 | # SteamVR兼容性(OpenGloves) 65 | 此项会用到OpenVR驱动程序去兼容SteamVR, 您可以到Steam下载: 66 | https://store.steampowered.com/app/1574050/OpenGloves/ 67 | 68 | GitHub上已公布的源代码: 69 | https://github.com/LucidVR/opengloves-driver 70 | 71 | # Other Languages 72 | **[English](https://github.com/LucidVR/lucidgloves/blob/main/README.md) | [简体中文](https://github.com/LucidVR/lucidgloves/blob/main/Readme_Languages/README_CN.md)** 73 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Controller/InputManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../../Config.h" 5 | #include "../../AdvancedConfig.h" 6 | 7 | 8 | #if (ENABLE_MEDIAN_FILTER || ((INTERFILTER_MODE != INTERFILTER_NONE) && (FLEXION_MIXING != MIXING_NONE))) 9 | #include 10 | #endif 11 | 12 | class InputManager 13 | { 14 | public: 15 | InputManager(); 16 | void setupInputs(); 17 | int analogPinRead(int pin); 18 | #if USING_MULTIPLEXER 19 | int readMux(byte pin); 20 | #endif 21 | void getFingerPositions(bool calibrating, bool reset, int* fingerPos); 22 | int analogReadDeadzone(int pin); 23 | int getJoyX(); 24 | int getJoyY(); 25 | bool getButton(byte pin); 26 | #if FLEXION_MIXING == MIXING_SINCOS 27 | int sinCosMix(int sinPin, int cosPin, int i); 28 | #endif 29 | void saveTravel(); 30 | void saveIntermediate(); 31 | void clearFlags(); 32 | bool isSavedLimits(); 33 | bool isSavedIntermediate(); 34 | void loadTravel(); 35 | void loadIntermediate(); 36 | private: 37 | // Add your private variables here 38 | bool savedInter = false; 39 | bool savedTravel = false; 40 | 41 | int maxFingers[2* NUM_FINGERS] = {0,0,0,0,0,0,0,0,0,0}; 42 | int minFingers[2* NUM_FINGERS] = {ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX}; 43 | int maxTravel[2*NUM_FINGERS] = {ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX}; 44 | 45 | #if FLEXION_MIXING == MIXING_SINCOS 46 | int sinMin[NUM_FINGERS] = {ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX}; 47 | int sinMax[NUM_FINGERS] = {0,0,0,0,0}; 48 | 49 | int cosMin[NUM_FINGERS] = {ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX, ANALOG_MAX}; 50 | int cosMax[NUM_FINGERS] = {0,0,0,0,0}; 51 | 52 | bool atanPositive[NUM_FINGERS] = {true, true, true, true, true}; 53 | 54 | 55 | int totalOffset1[NUM_FINGERS] = {0,0,0,0,0}; 56 | #endif 57 | 58 | #if ENABLE_MEDIAN_FILTER 59 | RunningMedian rmSamples[2* NUM_FINGERS] = { 60 | RunningMedian(MEDIAN_SAMPLES), 61 | RunningMedian(MEDIAN_SAMPLES), 62 | RunningMedian(MEDIAN_SAMPLES), 63 | RunningMedian(MEDIAN_SAMPLES), 64 | RunningMedian(MEDIAN_SAMPLES), 65 | RunningMedian(MEDIAN_SAMPLES), 66 | RunningMedian(MEDIAN_SAMPLES), 67 | RunningMedian(MEDIAN_SAMPLES), 68 | RunningMedian(MEDIAN_SAMPLES), 69 | RunningMedian(MEDIAN_SAMPLES) 70 | }; 71 | #endif 72 | 73 | #if ((INTERFILTER_MODE != INTERFILTER_NONE) && (FLEXION_MIXING == MIXING_SINCOS)) 74 | RunningMedian sinSamples[NUM_FINGERS] = { 75 | RunningMedian(INTERFILTER_SAMPLES), 76 | RunningMedian(INTERFILTER_SAMPLES), 77 | RunningMedian(INTERFILTER_SAMPLES), 78 | RunningMedian(INTERFILTER_SAMPLES), 79 | RunningMedian(INTERFILTER_SAMPLES) 80 | }; 81 | 82 | RunningMedian cosSamples[NUM_FINGERS] = { 83 | RunningMedian(INTERFILTER_SAMPLES), 84 | RunningMedian(INTERFILTER_SAMPLES), 85 | RunningMedian(INTERFILTER_SAMPLES), 86 | RunningMedian(INTERFILTER_SAMPLES), 87 | RunningMedian(INTERFILTER_SAMPLES) 88 | }; 89 | #endif 90 | 91 | 92 | 93 | }; 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![LucidGloves](https://cdn.discordapp.com/attachments/785135646082990120/873666310855360582/LucidGlovesBlackwbkgnd.png) 2 | 3 | # LucidGloves - Firmware and 3D Printer Files 4 | This repo contains the arduino firmware as well as the STL files for Prototypes 3 through 4 of the LucidVR glove. This is a finger tracking glove that allows you to use your hands in VR. Follow along with Lucas_VRTech's developments on his Tiktok page: 5 | https://www.tiktok.com/@lucas_vrtech 6 | 7 | # Building your own gloves 8 | **Start here at the wiki! https://github.com/LucidVR/lucidgloves/wiki** 9 | 10 | # Support 11 | Join the LucidVR discord server for assistance: 12 | https://discord.gg/lucidvr 13 | 14 | 15 | # Firmware 16 | Open the firmware files located in the firmware/lucidgloves-firmware folder. 17 | By default the firmware is configured for an arduino nano using serial. 18 | To configure the firmware, change the defines in the lucidgloves-firmware.ino file. 19 | 20 | **Configuration instructions are here: [Configuration Instructions](https://github.com/LucidVR/lucidgloves/wiki/Firmware-Setup-and-Customization-Tutorial).**\ 21 | **Firmware Troubleshooting Guide is here: [Firmware Troubleshooting Guide](https://github.com/LucidVR/lucidgloves/wiki/Firmware-Troubleshooting-Guide).** 22 | 23 | ## Tested boards: 24 | * Arduino Nano 25 | * ESP-WROOM-32 26 | 27 | ## Supported Communication Methods: 28 | * USB Serial 29 | * Bluetooth Serial (On ESP32 boards) 30 | * BLE (Soon, not up yet) 31 | 32 | # Hardware 33 | STL files for 3D printing are located in the hardware folder. 34 | *Prototype 4 models are currently experimental.* 35 | 36 | The assembly **for each hand** is as follows: 37 | 38 | For Prototypes 3 and 3.1 - 39 | * Spool (5x) 40 | * Tensioner (5x) 41 | * Cover (5x) 42 | * Holder (5x) 43 | * GuideRing(Will need to be resized) OR GuideNode(3.1) (2+ per finger, 1+ for thumb) 44 | * EndCap (1x per finger, will need to be resized to fit) 45 | 46 | For Prototypes 4 and 4.1 - 47 | * HapticSpool (5x) 48 | * Tensioner_GreenPot (5x) OR Tensioner_WLPot (5x) 49 | * SpoolCover (5x) 50 | * RigidMount (1x) (Left or right hand) 51 | * WLPotSlideHolder OR WLPotElasticHolder OR GreenPotSlideHolder (5x) 52 | * Quest2_MountSlider OR Vive3.0_MountSlider (1x) 53 | * GuideRing (Proto 3) (Will need to be resized) OR GuideNode (Proto 3.1) (2+ per finger, 1+ for thumb) 54 | * EndCap (Proto 3) (1x per finger, will need to be resized to fit) 55 | 56 | 57 | 58 | Guide for printing parts: [Printing guide](https://github.com/LucidVR/lucidgloves/wiki/Parts-Printing-Guides) 59 | 60 | 61 | **Required parts for each hand: [Parts Lists](https://github.com/LucidVR/lucidgloves/wiki/Parts-Lists)** 62 | Optional: 63 | * Joysticks for locomotion 64 | - Will be making a DIY treadmill eventually as well for those who would prefer that 65 | * Buttons (Most can be replaced with gestures) (One is required for autocalibration) 66 | 67 | More information will be available on the [LucidVR site](http://lucidvrtech.com/) very soon. 68 | * [Prototype 3/3.1 Building Tutorial](https://youtu.be/Qj4hqRKiy8g) 69 | * [Prototype 4/4.1 Building Tutorial](https://youtu.be/2yF-SJcg3zQ) 70 | 71 | # SteamVR Compatibility (OpenGloves) 72 | This project uses the OpenGloves OpenVR driver for compatibility with SteamVR, which is downloadable on Steam: 73 | https://store.steampowered.com/app/1574050/OpenGloves/ 74 | 75 | Source code available on GitHub: 76 | https://github.com/LucidVR/opengloves-driver 77 | 78 | # Other Languages 79 | **[English](https://github.com/LucidVR/lucidgloves/blob/main/README.md) | [简体中文](https://github.com/LucidVR/lucidgloves/blob/main/Readme_Languages/README_CN.md)** 80 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "Main.h" 2 | #include "Communication/SerialCommunication.h" 3 | #include "Communication/BTSerialCommunication.h" 4 | #include "Encoding/AlphaEncoding.h" 5 | #include "Encoding/LegacyEncoding.h" 6 | #include "Util/DataStructs.h" 7 | 8 | #define ALWAYS_CALIBRATING CALIBRATION_LOOPS == -1 9 | #define CALIB_OVERRIDE false 10 | #if USING_CALIB_PIN && COMMUNICATION == COMM_SERIAL && PIN_CALIB == 0 && !CALIB_OVERRIDE 11 | #error "You can't set your calibration pin to 0 over usb. You can calibrate with the BOOT button when using bluetooth only. Set CalibOverride to true to override this." 12 | #endif 13 | 14 | Main::Main() { 15 | // Constructor code here 16 | } 17 | 18 | void Main::setup() { 19 | pinMode(32, INPUT_PULLUP); 20 | pinMode(DEBUG_LED, OUTPUT); 21 | digitalWrite(DEBUG_LED, HIGH); 22 | 23 | #if COMMUNICATION == COMM_SERIAL 24 | comm = new SerialCommunication(); 25 | #elif COMMUNICATION == COMM_BTSERIAL 26 | comm = new BTSerialCommunication(); 27 | #elif COMMUNICATION == COMM_WIFISERIAL 28 | comm = new WIFISerialCommunication(); 29 | #else 30 | #error "Communication not set." 31 | #endif 32 | 33 | #if ENCODING == ENCODE_ALPHA 34 | encoding = new AlphaEncoding(); 35 | #elif ENCODING == ENCODE_LEGACY 36 | encoding = new LegacyEncoding(); 37 | #else 38 | #error "Encoding not set." 39 | #endif 40 | 41 | 42 | comm->start(); 43 | 44 | input.setupInputs(); 45 | 46 | #if USING_FORCE_FEEDBACK 47 | haptics.setupServoHaptics(); 48 | #endif 49 | 50 | #if defined(ESP32_DUAL_CORE_SET) 51 | xTaskCreatePinnedToCore( 52 | Main::getInputsWrapper, /* Function to implement the task */ 53 | "Get_Inputs", /* Name of the task */ 54 | 10000, /* Stack size in words */ 55 | this, /* Task input parameter */ 56 | tskIDLE_PRIORITY, /* Priority of the task */ 57 | &Task1, /* Task handle. */ 58 | 0); /* Core where the task should run */ 59 | #endif 60 | } 61 | 62 | void Main::loop() { 63 | 64 | if (comm->isOpen()){ 65 | 66 | #if USING_CALIB_PIN 67 | data.calib = input.getButton(PIN_CALIB) != INVERT_CALIB; 68 | if (data.calib) 69 | loops = 0; 70 | #else 71 | data.calib = false; 72 | #endif 73 | if (loops < CALIBRATION_LOOPS || ALWAYS_CALIBRATING){ 74 | calibrate = true; 75 | loops++; 76 | } 77 | else{ 78 | calibrate = false; 79 | } 80 | 81 | #if !defined(ESP32_DUAL_CORE_SET) 82 | input.getFingerPositions(calibrate, data.calib, fingerPos); 83 | #endif 84 | data.joyClick = input.getButton(PIN_JOY_BTN) != INVERT_JOY; 85 | 86 | #if TRIGGER_GESTURE 87 | data.triggerButton = gesture.triggerGesture(fingerPos); 88 | #else 89 | data.triggerButton = input.getButton(PIN_TRIG_BTN) != INVERT_TRIGGER; 90 | #endif 91 | 92 | data.aButton = input.getButton(PIN_A_BTN) != INVERT_A; 93 | data.bButton = input.getButton(PIN_B_BTN) != INVERT_B; 94 | 95 | #if GRAB_GESTURE 96 | data.grab = gesture.grabGesture(fingerPos); 97 | #else 98 | data.grab = input.getButton(PIN_GRAB_BTN) != INVERT_GRAB; 99 | #endif 100 | 101 | #if PINCH_GESTURE 102 | data.pinch = gesture.pinchGesture(fingerPos); 103 | #else 104 | data.pinch = input.getButton(PIN_PNCH_BTN) != INVERT_PINCH; 105 | #endif 106 | 107 | int fingerPosCopy[10]; 108 | int mutexTimeDone; 109 | data.menu = input.getButton(PIN_MENU_BTN) != INVERT_MENU; 110 | { 111 | #if defined(ESP32_DUAL_CORE_SET) 112 | int mutexTime = micros(); 113 | //const std::lock_guard lock(fingerPosMutex); 114 | fingerPosLock->lock(); 115 | mutexTimeDone = micros()-mutexTime; 116 | #endif 117 | //memcpy(fingerPosCopy, fingerPos, sizeof(fingerPos)); 118 | for (int i = 0; i < 10; i++){ 119 | fingerPosCopy[i] = fingerPos[i]; 120 | } 121 | #if defined(ESP32_DUAL_CORE_SET) 122 | fingerPosLock->unlock(); 123 | #endif 124 | 125 | } 126 | 127 | memcpy(data.fingers, fingerPosCopy, 5 * sizeof(int)); 128 | data.joyX = input.getJoyX(); 129 | data.joyY = input.getJoyY(); 130 | 131 | static char encodedString[100] = {0}; 132 | encoding->encode(data, encodedString); 133 | comm->output(encodedString); 134 | #if USING_FORCE_FEEDBACK 135 | static char received[100]; 136 | if (comm->readData(received)){ 137 | int hapticLimits[5]; 138 | //This check is a temporary hack to fix an issue with haptics on v0.5 of the driver, will make it more snobby code later 139 | if(String(received).length() >= 5) { 140 | DecodedData recievedData = encoding->decodeData(received); 141 | haptics.writeServoHaptics(recievedData.servoValues); 142 | if (recievedData.fields.specialCommandReceived){ 143 | Serial.println("Special command recieved!!!"); 144 | if (recievedData.command == "ClearData") 145 | input.clearFlags(); 146 | #if FLEXION_MIXING == MIXING_SINCOS 147 | else if (recievedData.command == "SaveInter") 148 | input.saveIntermediate(); 149 | #endif 150 | else if (recievedData.command == "SaveTravel") 151 | input.saveTravel(); 152 | } 153 | } 154 | } 155 | #endif 156 | #if defined(ESP32) 157 | vTaskDelay(LOOP_TIME); 158 | #else 159 | delay(LOOP_TIME); 160 | #endif 161 | } 162 | } 163 | 164 | 165 | #if defined(ESP32_DUAL_CORE_SET) 166 | void Main::getInputs(){ 167 | for(;;){ 168 | { 169 | fingerPosLock->lock(); 170 | input.getFingerPositions(calibrate, data.calib, fingerPos); //Save finger positions in thread 171 | 172 | fingerPosLock->unlock(); 173 | } 174 | threadLoops++; 175 | if (threadLoops%100 == 0){ 176 | vTaskDelay(1); //keep watchdog fed 177 | } 178 | delayMicroseconds(1); 179 | } 180 | } 181 | 182 | void Main::getInputsWrapper(void* _this) { 183 | // Cast the void* parameter back to a Main* and call getInputs on it 184 | static_cast(_this)->getInputs(); 185 | } 186 | 187 | #endif 188 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/Config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "src/Util/ConfigUtils.h" 3 | #include "AdvancedConfig.h" 4 | 5 | //LUCIDGLOVES CONFIGURATION SETTINGS :) 6 | 7 | //This is the configuration file, main structure in _main.ino 8 | //CONFIGURATION SETTINGS: 9 | #define COMMUNICATION COMM_SERIAL //Which communication to use. Options are: COMM_SERIAL (usb), COMM_BTSERIAL (bluetooth), COMM_WIFISERIAL (wifi) 10 | //serial over USB 11 | #define SERIAL_BAUD_RATE 115200 12 | 13 | //serial over Bluetooth 14 | #define BTSERIAL_DEVICE_NAME "lucidgloves-left" 15 | 16 | // serial over WIFI 17 | #if COMMUNICATION == COMM_WIFISERIAL 18 | #define ssid "Your_Wifi_SSID"; 19 | #define password "Your_Wifi_Password"; 20 | #define host "Your_host_ip"; 21 | #define port 65432; // port of the tcp server 22 | #endif 23 | 24 | //ANALOG INPUT CONFIG 25 | #define USING_SPLAY false //whether or not your glove tracks splay. - tracks the side to side "wag" of fingers. Requires 5 more inputs. 26 | #define USING_MULTIPLEXER false //Whether or not you are using a multiplexer for inputs 27 | #define FLIP_FLEXION false //Flip values from potentiometers (for fingers!) if they are backwards 28 | #define FLIP_SPLAY true //Flip values for splay 29 | 30 | 31 | //Gesture enables, make false to use button override 32 | #define TRIGGER_GESTURE true 33 | #define GRAB_GESTURE true 34 | #define PINCH_GESTURE true 35 | 36 | 37 | //BUTTON INVERT 38 | //If a button registers as pressed when not and vice versa (eg. using normally-closed switches), 39 | //you can invert their behaviour here by setting their line to true. 40 | //If unsure, set to false 41 | #define INVERT_A false 42 | #define INVERT_B false 43 | #define INVERT_JOY false 44 | #define INVERT_MENU false 45 | #define INVERT_CALIB false 46 | //These only apply with gesture button override: 47 | #define INVERT_TRIGGER false 48 | #define INVERT_GRAB false 49 | #define INVERT_PINCH false 50 | 51 | 52 | //joystick configuration 53 | #define JOYSTICK_BLANK true //make true if not using the joystick 54 | #define JOY_FLIP_X false 55 | #define JOY_FLIP_Y false 56 | #define JOYSTICK_DEADZONE 10 //deadzone in the joystick to prevent drift (in percent) 57 | 58 | #define NO_THUMB false //If for some reason you don't want to track the thumb 59 | 60 | #define USING_CALIB_PIN true //When PIN_CALIB is shorted (or it's button pushed) it will reset calibration if this is on. 61 | 62 | #define USING_FORCE_FEEDBACK true //Force feedback haptics allow you to feel the solid objects you hold 63 | #define FLIP_FORCE_FEEDBACK true 64 | #define SERVO_SCALING false //dynamic scaling of servo motors 65 | 66 | #if defined(ESP32) 67 | //(This configuration is for ESP32 DOIT V1 so make sure to change if you're on another board) 68 | //To use a pin on a multiplexer, use MUX(pin). So for example pin 15 on a mux would be MUX(15). 69 | #define PIN_PINKY 32//These 5 are for flexion 70 | #define PIN_RING 35 71 | #define PIN_MIDDLE 34 72 | #define PIN_INDEX 39 73 | #define PIN_THUMB 36 74 | #define PIN_JOY_X 33 75 | #define PIN_JOY_Y 25 76 | #define PIN_JOY_BTN 26 77 | #define PIN_A_BTN 27 78 | #define PIN_B_BTN 14 79 | #define PIN_TRIG_BTN 12 //unused if gesture set 80 | #define PIN_GRAB_BTN 13 //unused if gesture set 81 | #define PIN_PNCH_BTN 23 //unused if gesture set 82 | #define PIN_CALIB 15 //button for recalibration (You can set this to GPIO0 to use the BOOT button, but only when using Bluetooth.) 83 | #define DEBUG_LED 2 84 | #define PIN_PINKY_MOTOR 19 //used for force feedback 85 | #define PIN_RING_MOTOR 18 //^ 86 | #define PIN_MIDDLE_MOTOR 5 //^ 87 | #define PIN_INDEX_MOTOR 17 //^ 88 | #define PIN_THUMB_MOTOR 16 //^ 89 | #define PIN_MENU_BTN 34 90 | 91 | //Splay pins. Only used for splay tracking gloves. Use MUX(pin) if you are using a multiplexer for it. 92 | #define PIN_PINKY_SPLAY MUX(14) 93 | #define PIN_RING_SPLAY MUX(11) 94 | #define PIN_MIDDLE_SPLAY MUX(8) 95 | #define PIN_INDEX_SPLAY MUX(5) 96 | #define PIN_THUMB_SPLAY MUX(2) 97 | 98 | 99 | //Select pins for multiplexers, set as needed if using a mux. You can add or remove pins as needed depending on how many select pins your mux needs. 100 | #define PINS_MUX_SELECT 27, /*S0 pin*/ \ 101 | 14, /*S1 pin*/ \ 102 | 12, /*S2 pin*/ \ 103 | 13 /*S3 pin (if your mux is 3-bit like 74HC4051 then you can remove this line and the backslash before it.)*/ 104 | 105 | #define MUX_INPUT 35 //the input or SIG pin of the multiplexer. This can't be a mux pin. 106 | 107 | //Signal mixing for finger values. Options are: MIXING_NONE, MIXING_SINCOS 108 | //For double rotary hall effect sensors use MIXING_SINCOS. For potentiometers use MIXING_NONE. 109 | #define FLEXION_MIXING MIXING_NONE 110 | //Secondary analog pins for mixing flexion values. Only used by MIXING_SINCOS. Use MUX(pin) if you are using a multiplexer for it. 111 | #define PIN_PINKY_SECOND MUX(13) 112 | #define PIN_RING_SECOND MUX(10) 113 | #define PIN_MIDDLE_SECOND MUX(7) 114 | #define PIN_INDEX_SECOND MUX(4) 115 | #define PIN_THUMB_SECOND MUX(1) 116 | 117 | //PINS CONFIGURATION 118 | #elif defined(__AVR__) 119 | //(This configuration is for Arduino Nano so make sure to change if you're on another board) 120 | #define PIN_PINKY A0 121 | #define PIN_RING A1 122 | #define PIN_MIDDLE A2 123 | #define PIN_INDEX A3 124 | #define PIN_THUMB A4 125 | #define PIN_JOY_X A6 126 | #define PIN_JOY_Y A7 127 | #define PIN_JOY_BTN 7 128 | #define PIN_A_BTN 8 129 | #define PIN_B_BTN 9 130 | #define PIN_TRIG_BTN 10 //unused if gesture set 131 | #define PIN_GRAB_BTN 11 //unused if gesture set 132 | #define PIN_PNCH_BTN 12 //unused if gesture set 133 | #define PIN_CALIB 13 //button for recalibration 134 | #define DEBUG_LED LED_BUILTIN 135 | #define PIN_PINKY_MOTOR 2 //used for force feedback 136 | #define PIN_RING_MOTOR 3 //^ 137 | #define PIN_MIDDLE_MOTOR 4 //^ 138 | #define PIN_INDEX_MOTOR 5 //^ 139 | #define PIN_THUMB_MOTOR 6 //^ 140 | #define PIN_MENU_BTN 8 141 | 142 | //Splay pins. Only used for splay tracking gloves. Use MUX(pin) if you are using a multiplexer for it. 143 | #define PIN_PINKY_SPLAY MUX(10) 144 | #define PIN_RING_SPLAY MUX(11) 145 | #define PIN_MIDDLE_SPLAY MUX(12) 146 | #define PIN_INDEX_SPLAY MUX(13) 147 | #define PIN_THUMB_SPLAY MUX(14) 148 | 149 | //Select pins for multiplexers, set as needed if using a mux. You can add or remove pins as needed depending on how many select pins your mux needs. 150 | #define PINS_MUX_SELECT 10, /*S0 pin*/ \ 151 | 11, /*S1 pin*/ \ 152 | 12, /*S2 pin*/ \ 153 | 13 /*S3 pin (if your mux is 3-bit like 74HC4051 then you can remove this line and the backslash before it.)*/ 154 | 155 | #define MUX_INPUT A0 //the input or SIG pin of the multiplexer. This can't be a mux pin. 156 | 157 | //Signal mixing for finger values. Options are: MIXING_NONE, MIXING_SINCOS 158 | //For double rotary hall effect sensors use MIXING_SINCOS. For potentiometers use MIXING_NONE. 159 | #define FLEXION_MIXING MIXING_NONE 160 | //Secondary analog pins for mixing. Only used by MIXING_SINCOS. Use MUX(pin) if you are using a multiplexer for it. 161 | #define PIN_PINKY_SECOND MUX(1) 162 | #define PIN_RING_SECOND MUX(3) 163 | #define PIN_MIDDLE_SECOND MUX(5) 164 | #define PIN_INDEX_SECOND MUX(7) 165 | #define PIN_THUMB_SECOND MUX(9) 166 | #endif 167 | -------------------------------------------------------------------------------- /firmware/lucidgloves-firmware/src/Controller/InputManager.cpp: -------------------------------------------------------------------------------- 1 | #include "InputManager.h" 2 | InputManager::InputManager() { 3 | // Constructor logic here... 4 | } 5 | 6 | void InputManager::setupInputs() { 7 | 8 | EEPROM.begin(0x78 + 1); 9 | if (isSavedLimits()){ 10 | savedTravel = true; 11 | loadTravel(); 12 | } 13 | #if FLEXION_MIXING == MIXING__SINCOS 14 | if (isSavedIntermediate()){ 15 | savedInter = true; 16 | loadIntermediate(); 17 | } 18 | #endif 19 | 20 | pinMode(PIN_JOY_BTN, INPUT_PULLUP); 21 | pinMode(PIN_A_BTN, INPUT_PULLUP); 22 | pinMode(PIN_B_BTN, INPUT_PULLUP); 23 | 24 | pinMode(PIN_MENU_BTN, INPUT_PULLUP); 25 | 26 | #if !TRIGGER_GESTURE 27 | pinMode(PIN_TRIG_BTN, INPUT_PULLUP); 28 | #endif 29 | 30 | #if !GRAB_GESTURE 31 | pinMode(PIN_GRAB_BTN, INPUT_PULLUP); 32 | #endif 33 | 34 | #if !PINCH_GESTURE 35 | pinMode(PIN_PNCH_BTN, INPUT_PULLUP); 36 | #endif 37 | 38 | #if USING_CALIB_PIN 39 | pinMode(PIN_CALIB, INPUT_PULLUP); 40 | #endif 41 | 42 | #if USING_MULTIPLEXER 43 | //pinMode(MUX_INPUT, INPUT); 44 | { 45 | byte selectPins[] = {PINS_MUX_SELECT}; 46 | for (int i = 0; i < sizeof(selectPins); i++){ 47 | pinMode(selectPins[i], OUTPUT); 48 | } 49 | } 50 | #endif 51 | } 52 | 53 | int InputManager::analogPinRead(int pin) { 54 | #if USING_MULTIPLEXER 55 | if (ISMUX(pin)){ 56 | return readMux(UNMUX(pin)); 57 | } 58 | else{ 59 | return analogRead(pin); 60 | } 61 | #else 62 | return analogRead(UNMUX(pin)); 63 | #endif 64 | } 65 | 66 | // Other methods follow the same pattern... 67 | 68 | #if USING_MULTIPLEXER 69 | int InputManager::readMux(byte pin) { 70 | byte selectPins[] = {PINS_MUX_SELECT}; 71 | int numSelectPins = sizeof(selectPins) / sizeof(selectPins[0]); 72 | 73 | for (int i = numSelectPins - 1; i > -1; i--){ 74 | digitalWrite(selectPins[i], (pin & (1 << i)) ? HIGH : LOW); 75 | } 76 | 77 | delayMicroseconds(MULTIPLEXER_DELAY); 78 | return analogRead(MUX_INPUT); 79 | } 80 | #endif 81 | 82 | void InputManager::getFingerPositions(bool calibrating, bool reset, int* fingerPos) { 83 | #if FLEXION_MIXING == MIXING_NONE //no mixing, just linear 84 | int rawFingersFlexion[NUM_FINGERS] = {NO_THUMB?0:analogPinRead(PIN_THUMB), analogPinRead(PIN_INDEX), analogPinRead(PIN_MIDDLE), analogPinRead(PIN_RING), analogPinRead(PIN_PINKY)}; 85 | 86 | #elif FLEXION_MIXING == MIXING_SINCOS 87 | int rawFingersFlexion[NUM_FINGERS] = {NO_THUMB?0:sinCosMix(PIN_THUMB, PIN_THUMB_SECOND, 0 ), 88 | sinCosMix(PIN_INDEX, PIN_INDEX_SECOND, 1 ), 89 | sinCosMix(PIN_MIDDLE,PIN_MIDDLE_SECOND,2 ), 90 | sinCosMix(PIN_RING, PIN_RING_SECOND, 3 ), 91 | sinCosMix(PIN_PINKY, PIN_PINKY_SECOND, 4 )}; 92 | 93 | #endif 94 | 95 | int rawFingers[2 * NUM_FINGERS]; 96 | 97 | #if USING_SPLAY 98 | int rawFingersSplay[NUM_FINGERS] = {NO_THUMB?0:analogPinRead(PIN_THUMB_SPLAY), 99 | analogPinRead(PIN_INDEX_SPLAY), 100 | analogPinRead(PIN_MIDDLE_SPLAY), 101 | analogPinRead(PIN_RING_SPLAY), 102 | analogPinRead(PIN_PINKY_SPLAY)}; 103 | #else 104 | int rawFingersSplay[NUM_FINGERS] = {0,0,0,0,0}; 105 | #endif 106 | //memcpy(rawFingers, rawFingersFlexion, 5); //memcpy doesn't seem to work here 107 | //memcpy(&rawFingers[5], rawFingersSplay, 5); 108 | 109 | for (int i = 0; i < NUM_FINGERS; i++){ 110 | rawFingers[i] = rawFingersFlexion[i]; 111 | rawFingers[i+NUM_FINGERS] = rawFingersSplay[i]; 112 | } 113 | 114 | 115 | //flip pot values if needed 116 | #if FLIP_FLEXION 117 | for (int i = 0; i < NUM_FINGERS; i++){ 118 | rawFingers[i] = ANALOG_MAX - rawFingers[i]; 119 | } 120 | #endif 121 | 122 | #if FLIP_SPLAY 123 | for (int i = NUM_FINGERS; i < 2 * NUM_FINGERS; i++){ 124 | rawFingers[i] = ANALOG_MAX - rawFingers[i]; 125 | } 126 | #endif 127 | 128 | #if ENABLE_MEDIAN_FILTER 129 | for (int i = 0; i < 2 * NUM_FINGERS; i++){ 130 | rmSamples[i].add( rawFingers[i] ); 131 | rawFingers[i] = rmSamples[i].getMedian(); 132 | } 133 | #endif 134 | 135 | //reset max and mins as needed 136 | if (reset){ 137 | for (int i = 0; i <2 * NUM_FINGERS; i++){ 138 | #if FLEXION_MIXING == MIXING_SINCOS 139 | if (i < NUM_FINGERS) 140 | totalOffset1[i] = 0; 141 | #endif 142 | maxFingers[i] = INT_MIN; 143 | minFingers[i] = INT_MAX; 144 | } 145 | } 146 | 147 | //if during the calibration sequence, make sure to update max and mins 148 | if (calibrating){ 149 | for (int i = 0; i < 2*NUM_FINGERS; i++){ 150 | if (rawFingers[i] > maxFingers[i]) 151 | #if CLAMP_SENSORS 152 | maxFingers[i] = ( rawFingers[i] <= CLAMP_MAX )? rawFingers[i] : CLAMP_MAX; 153 | #else 154 | maxFingers[i] = rawFingers[i]; 155 | if (savedTravel && (maxFingers[i] - minFingers[i] > maxTravel[i])) 156 | minFingers[i] = maxFingers[i] - maxTravel[i]; 157 | #endif 158 | if (rawFingers[i] < minFingers[i]) 159 | #if CLAMP_SENSORS 160 | minFingers[i] = ( rawFingers[i] >= CLAMP_MIN )? rawFingers[i] : CLAMP_MIN; 161 | #else 162 | minFingers[i] = rawFingers[i]; 163 | if (savedTravel && (maxFingers[i] - minFingers[i] > maxTravel[i])) 164 | maxFingers[i] = minFingers[i] + maxTravel[i]; 165 | #endif 166 | } 167 | } 168 | 169 | for (int i = 0; i ANALOG_MAX) 176 | fingerPos[i] = ANALOG_MAX; 177 | #endif 178 | } 179 | else { 180 | fingerPos[i] = ANALOG_MAX / 2; 181 | } 182 | 183 | } 184 | } 185 | 186 | int InputManager::analogReadDeadzone(int pin){ 187 | int raw = analogPinRead(pin); 188 | if (abs(ANALOG_MAX/2 - raw) < JOYSTICK_DEADZONE * ANALOG_MAX / 100) 189 | return ANALOG_MAX/2; 190 | else 191 | return raw; 192 | } 193 | 194 | int InputManager::getJoyX(){ 195 | #if JOYSTICK_BLANK 196 | return ANALOG_MAX/2; 197 | #elif JOY_FLIP_X 198 | return ANALOG_MAX - analogReadDeadzone(PIN_JOY_X); 199 | #else 200 | return analogReadDeadzone(PIN_JOY_X); 201 | #endif 202 | } 203 | 204 | int InputManager::getJoyY(){ 205 | #if JOYSTICK_BLANK 206 | return ANALOG_MAX/2; 207 | #elif JOY_FLIP_Y 208 | return ANALOG_MAX - analogReadDeadzone(PIN_JOY_Y); 209 | #else 210 | return analogReadDeadzone(PIN_JOY_Y); 211 | #endif 212 | } 213 | 214 | bool InputManager::getButton(byte pin){ 215 | return digitalRead(pin) != HIGH; 216 | } 217 | 218 | #if FLEXION_MIXING == MIXING_SINCOS 219 | //mixing 220 | int InputManager::sinCosMix(int sinPin, int cosPin, int i){ 221 | 222 | int sinRaw = analogPinRead(sinPin); 223 | int cosRaw = analogPinRead(cosPin); 224 | 225 | #if INTERFILTER_MODE != INTERFILTER_NONE 226 | sinSamples[i].add(sinRaw); 227 | cosSamples[i].add(cosRaw); 228 | int sinCalib = sinSamples[i].getMedian(); 229 | int cosCalib = cosSamples[i].getMedian(); 230 | #if INTERFILTER_MODE == INTERFILTER_ALL 231 | sinRaw = sinCalib; 232 | cosRaw = cosCalib; 233 | #endif 234 | #else 235 | int sinCalib = sinRaw; 236 | int cosCalib = cosRaw; 237 | #endif 238 | 239 | if (!savedInter){ 240 | //scaling 241 | sinMin[i] = min(sinCalib, sinMin[i]); 242 | sinMax[i] = max(sinCalib, sinMax[i]); 243 | 244 | cosMin[i] = min(cosCalib, cosMin[i]); 245 | cosMax[i] = max(cosCalib, cosMax[i]); 246 | } 247 | 248 | int sinScaled = map(sinRaw, sinMin[i], sinMax[i], -ANALOG_MAX, ANALOG_MAX); 249 | int cosScaled = map(cosRaw, cosMin[i], cosMax[i], -ANALOG_MAX, ANALOG_MAX); 250 | 251 | 252 | //trigonometry stuffs 253 | double angleRaw = atan2(sinScaled, cosScaled); 254 | 255 | //counting rotations 256 | if (((angleRaw > 0) != atanPositive[i]) && sinScaled > cosScaled){ 257 | totalOffset1[i] += atanPositive[i]?1:-1; 258 | } 259 | atanPositive[i] = angleRaw > 0; 260 | double totalAngle = angleRaw + 2*PI * totalOffset1[i]; 261 | 262 | 263 | return (int)(totalAngle * ANALOG_MAX); 264 | 265 | } 266 | #endif 267 | 268 | void InputManager::saveTravel() 269 | { 270 | byte flags = EEPROM.read(0x00); 271 | flags |= 0x01; // Set bit 0 272 | EEPROM.write(0x00, flags); // Save clamping saved limits flag 273 | 274 | int addr = 0x01; // Start address for flexion and splay values 275 | 276 | for (int i = 0; i < 2*NUM_FINGERS; i++) { 277 | int diff = maxFingers[i] - minFingers[i]; // Calculate the difference 278 | EEPROM.put(addr, diff); // Store the difference into the EEPROM at the current address 279 | addr += sizeof(int); // Increment the address by 4 because we're storing int values 280 | } 281 | 282 | EEPROM.commit(); // Ensure changes are written to EEPROM 283 | 284 | loadTravel(); 285 | } 286 | 287 | void InputManager::saveIntermediate() 288 | { 289 | #if FLEXION_MIXING == MIXING_SINCOS 290 | byte flags = EEPROM.read(0x00); 291 | flags |= 0x02; // Set bit 1 292 | EEPROM.write(0x00, flags); // Save intermediate values saved flag 293 | 294 | int address = 0x29; // Start address for sin and cos values 295 | 296 | for(int i = 0; i < NUM_FINGERS; i++) 297 | { 298 | EEPROM.put(address, sinMax[i]); 299 | address += sizeof(int); 300 | EEPROM.put(address, sinMin[i]); 301 | address += sizeof(int); 302 | EEPROM.put(address, cosMax[i]); 303 | address += sizeof(int); 304 | EEPROM.put(address, cosMin[i]); 305 | address += sizeof(int); 306 | } 307 | 308 | EEPROM.commit(); // Ensure changes are written to EEPROM 309 | #endif 310 | } 311 | 312 | void InputManager::clearFlags() 313 | { 314 | EEPROM.write(0x00, 0x00); // Clear the flags 315 | EEPROM.commit(); // Ensure the changes are written to EEPROM 316 | } 317 | 318 | bool InputManager::isSavedLimits() 319 | { 320 | byte flags = EEPROM.read(0x00); 321 | return flags & 0x01; // Check bit 0 322 | } 323 | 324 | bool InputManager::isSavedIntermediate() 325 | { 326 | byte flags = EEPROM.read(0x00); 327 | return flags & 0x02; // Check bit 1 328 | } 329 | 330 | void InputManager::loadTravel() 331 | { 332 | byte flags = EEPROM.read(0x00); 333 | if (!(flags & 0x01)) return; // If clamping saved limits flag is not set, do nothing 334 | 335 | int addr = 0x01; // Start address for flexion and splay values 336 | 337 | for (int i = 0; i < 2*NUM_FINGERS; i++) { 338 | EEPROM.get(addr, maxTravel[i]); // Load the max travel value from the EEPROM at the current address 339 | addr += sizeof(int); // Increment the address by 4 because we're storing int values 340 | } 341 | } 342 | 343 | void InputManager::loadIntermediate() 344 | { 345 | #if FLEXION_MIXING == MIXING_SINCOS 346 | byte flags = EEPROM.read(0x00); 347 | if (!(flags & 0x02)) return; // If intermediate values saved flag is not set, do nothing 348 | 349 | int address = 0x29; // Start address for sin and cos values 350 | 351 | for(int i = 0; i < NUM_FINGERS; i++) 352 | { 353 | EEPROM.get(address, sinMax[i]); 354 | address += sizeof(int); 355 | 356 | EEPROM.get(address, sinMin[i]); 357 | address += sizeof(int); 358 | 359 | EEPROM.get(address, cosMax[i]); 360 | address += sizeof(int); 361 | 362 | EEPROM.get(address, cosMin[i]); 363 | address += sizeof(int); 364 | } 365 | #endif 366 | } 367 | 368 | 369 | 370 | --------------------------------------------------------------------------------