Gesture Communication System

by Ekna in Circuits > Assistive Tech

607 Views, 7 Favorites, 0 Comments

Gesture Communication System

IMG-20260204-WA0014.jpg
IMG-20260204-WA0090.jpg

Gesture Communication System: The All-in-One Assistive Smart Glove Featuring Gesture Communication, Automation & Health Monitoring


Introduction

In a world where communication is vital, individuals with sensory impairments (deaf, mute, or blind) often face significant barriers. This project is a comprehensive assistive technology solution: a Smart Glove.

This device serves three main purposes:

  1. Communication: Converts hand gestures into SMS text messages for caregivers.
  2. Home Automation: Allows the user to control home appliances (Lights, Fans) using simple finger bends.
  3. Health Monitoring: Continuously tracks the user's Heart Rate (BPM) and alerts caregivers if it becomes abnormal.

This guide will walk you through the theory, the circuit build, the calibration process, and the final coding.

Supplies

Untitled design.png

Building this project requires components for two separate units: the wearable Glove (Transmitter) and the Home Unit (Receiver).

Microcontrollers:

  1. 1x Arduino Nano: The heart of the wearable glove.
  2. 1x Arduino Uno: To manage the home automation and display unit.

Sensors:

  1. 5x Flex Sensors (2.2 inch): To detect the bending of each finger.
  2. 1x Pulse/Heart Rate Sensor: For continuous health monitoring.

Communication Modules:

  1. 1x SIM800L GSM Module: To send emergency and gesture-based SMS messages.
  2. 2x HC-05 Bluetooth Modules: Set up as "Master" (on the glove) and "Slave" (on the home unit).

Displays:

  1. 1x OLED Display (0.96" I2C): Small enough to mount on the glove to show status.
  2. 1x LCD Display (16x2 I2C): To show the status of home appliances at the receiver.

Actuators (Relays):

  1. 1x 2-Channel Relay Module: To control the Light Bulb and the Wall Socket.
  2. 1x Single Channel Relay Module: To control the 12V DC Fan.

(You can go for a three or four channel relay)

Power & Converters:

  1. 1x 12V AC-to-DC Converter: This takes your home’s wall power and provides 12V for the system.
  2. 1x Buck Converter (Step-Down): Connects to the 12V output to provide a steady 5V to the Arduino Uno.
  3. 1x 9V or LiPo Battery: To power the Arduino Nano on the glove for portability. In this case a powerbank was used instead.

Passive Components & Miscellaneous:

  1. 5x 10kΩ Resistors: Essential for the flex sensor voltage dividers.
  2. 1x Anti-static/ESD Glove: The base for your wearable tech.
  3. Jumper wires, Electrical wires, Breadboards, or a Custom PCB.
  4. 12V DC Fan, Light Bulb, and Socket.
  5. Strap: to tighten the heart-rate sensor to your wrists

Software:

  1. Arduino IDE: For coding and uploading to your microcontrollers.

Understanding the System Architecture

Screenshot 2026-02-05 12.58.49 AM.png
Screenshot 2026-02-05 12.59.52 AM.png


Before building, it is important to understand how the system works. The system operates in three distinct modes:

  1. Communication Mode: The Arduino reads the flex sensors. If a specific finger is bent (e.g., Ring Finger), it triggers the GSM module to send a specific SMS (e.g., "I want water") to a designated number/caregiver.
  2. Automation Mode: If the user switches modes, bending fingers will send Bluetooth signals to the Receiver Unit (Arduino Uno) to toggle relays (Lights ON/OFF).
  3. BPM Mode (Idle): When no gestures are detected for a set time, the system enters Health Monitoring mode, displaying the Heart Rate on the OLED and sending alerts when heart rate is above or below normal heart rate levels.


To make this build manageable, we will treat it as three "Mini Projects" that we will integrate at the end.

  1. Phase 1: Communication Mode: Wiring flex sensors, setting up the OLED display, and testing GSM SMS capabilities.
  2. Phase 2: Automation Mode: Building the receiver unit with relays and testing AC/DC load switching.
  3. Phase 3: Health & Integration: Adding the heart rate sensor and combining all codes into one "Brain" system.


Communication Mode (The Flex Sensor)

Screenshot 2026-02-05 1.05.03 AM.png
IMG-20260204-WA0031.jpg
IMG-20260206-WA0072.jpg


In this phase, we build the sensory part of the glove. The Arduino Nano will read the bending of fingers to trigger events.

Step A: Wiring the Flex Sensors

The flex sensors act as variable resistors. As you bend them, resistance increases. We need to create a Voltage Divider circuit for each finger.

Wiring:

  1. Connect one leg of every Flex Sensor to +5V.
  2. Connect the other leg to an Analog Pin (A0, A1, A2, A3, A6) AND to GND via a 10kΩ Resistor.
  3. Thumb (Flex Sensor) = A6
  4. Index (Flex Sensor) = A3
  5. Middle (Flex Sensor) = A2
  6. Ring (Flex Sensor)= A1
  7. Pinky (Flex Sensor) = A0


Step B: Determining Flex Thresholds

Every flex sensor is different. You need to find the "bend value" where the Arduino knows a finger is bent.

  1. Upload the Threshold Test Code below to your Arduino Nano.
  2. Open the Serial Monitor (9600 baud).
  3. Note the value when the finger is straight (e.g., 20) and fully bent (e.g., 150).
  4. Pick a value in between (e.g., 80) to be your "Threshold."

Code: Flex Sensor Threshold Test

// Pin definitions
const int thumbPin = A6;
const int indexPin = A3;
const int middlePin = A2;
const int ringPin = A1;
const int pinkyPin = A0;

void setup() {
// Initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}

void loop() {
// Read the input on analog pins:
int thumbValue = analogRead(thumbPin);
int indexValue = analogRead(indexPin);
int middleValue = analogRead(middlePin);
int ringValue = analogRead(ringPin);
int pinkyValue = analogRead(pinkyPin);

// Print the results to the Serial Monitor:
Serial.print("Thumb: ");
Serial.print(thumbValue);
Serial.print("\tIndex: ");
Serial.print(indexValue);
Serial.print("\tMiddle: ");
Serial.print(middleValue);
Serial.print("\tRing: ");
Serial.print(ringValue);
Serial.print("\tPinky: ");
Serial.println(pinkyValue);

// Wait a bit before reading again
delay(500);
}


Once you have picked an average threshold, "bend value" where the Arduino knows a finger is bent, we can proceed to the next step of the communication mode!

Setting Up the OLED Display + Flex Sensors

IMG-20260206-WA0058.jpg

Step C: OLED + Flex sensors Setup

The OLED screen serves as the visual interface for the glove, displaying the text translated from your gestures, current system status, and heart rate readings. In this step we are going to assign text to the five flex sensors and display unto the OLED screen.

Wiring Connections (Nano to OLED):

  1. VCC5V
  2. GNDGND
  3. SDAA4 (Analog Pin 4)
  4. SCLA5 (Analog Pin 5)

Upload this code to your Arduino Nano once you have secured your flex sensor and oled display connections;

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// OLED display configuration
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64 // Change to 32 if your OLED is 128x32
#define OLED_RESET -1

// Flex sensor pins (Thumb → Pinky)
#define THUMB_PIN A6
#define INDEX_PIN A3
#define MIDDLE_PIN A2
#define RING_PIN A1
#define PINKY_PIN A0

// Number of flex sensors
#define NUM_SENSORS 5

// Create OLED display object
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Arrays for sensor handling (Thumb → Pinky order)
int sensorPins[NUM_SENSORS] = {
THUMB_PIN,
INDEX_PIN,
MIDDLE_PIN,
RING_PIN,
PINKY_PIN
};

int sensorValues[NUM_SENSORS];
bool bendDetected[NUM_SENSORS] = {false, false, false, false, false};

// Scrolling text
const char scrollText[] = "Gesture Communication System ";
int scrollTextLength = sizeof(scrollText) - 1;
int scrollPosition = 0;

// Bend detection threshold (adjust after calibration)
const int BEND_THRESHOLD = 130;

void setup() {
Serial.begin(115200);

// Initialize OLED display (I2C address 0x3C)
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
while (true);
}

display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.display();
}

void loop() {

// Read all flex sensors
for (int i = 0; i < NUM_SENSORS; i++) {
sensorValues[i] = analogRead(sensorPins[i]);

if (sensorValues[i] < BEND_THRESHOLD) {
bendDetected[i] = true;
} else {
bendDetected[i] = false;
}

// Debug output
Serial.print("Sensor ");
Serial.print(i);
Serial.print(": ");
Serial.println(sensorValues[i]);
}

display.clearDisplay();
display.setCursor(0, 0);

bool bendDetectedFlag = false;

// Display message based on first detected bend
for (int i = 0; i < NUM_SENSORS; i++) {
if (bendDetected[i]) {
bendDetectedFlag = true;

switch (i) {
case 0: // Thumb
display.println("I need medicine");
break;

case 1: // Index
display.println("I need water");
break;

case 2: // Middle
display.println("I need help");
break;

case 3: // Ring
display.println("Call my family");
break;

case 4: // Pinky
display.println("Emergency!");
break;
}
break; // Show only one message at a time
}
}

// Scroll system text when no gesture is detected
if (!bendDetectedFlag) {
display.setTextSize(1);
display.setCursor(0, 0);

for (int i = 0; i < 16; i++) {
int pos = (scrollPosition + i) % scrollTextLength;
display.print(scrollText[pos]);
}

scrollPosition++;
if (scrollPosition >= scrollTextLength) {
scrollPosition = 0;
}
}

display.display();
delay(100);
}


You can head to TinkerCad and play with a little simulation which utilities an Arduino Uno and five flex sensors>>>>>>https://www.tinkercad.com/things/1n5bEEMZVen-gesture-communication-system?sharecode=76JfNZ5mmcOaCuwczODbpxwzezXTLhdTDQ_hjrhn5FE

You can equally copy the code there if you are using an Arduino Uno for your OLED Display Test.


Important Note:

The codes in this project are designed for the Arduino Nano for the gesture and health monitoring functions. The portions of the code that control the automation mode on the utility end are assigned to the Arduino Uno. Using a different Arduino board for either function may require pin reassignment and minor code modifications.

Setting Up the GSM (SIM800L)

5_.jpg
Screenshot 2026-02-04 11.50.25 PM.png

This is a big one so brace yourself, the SIM800L module enables the glove to send SMS alerts for specific gestures. This requires a robust power connection and specific wiring to the Arduino Nano's digital pins for software serial communication.


Check out Last Minute Engineers for more details on setting up the GSM Module if you feel stuck>>>>>>>>https://lastminuteengineers.com/sim800l-gsm-module-arduino-tutorial/


Wiring Connections (Nano to SIM800L):

  1. VCCExternal 3.7V - 4.2V Power Source
  2. GNDExternal Power GND (Connect this to Arduino GND as well)
  3. RXD3 (Digital Pin 3)
  4. TXD2 (Digital Pin 2)


Note: The SIM800L is very sensitive to power fluctuations. A dedicated external power supply capable of delivering at least 2A (like a Li-Po battery or a buck converter) is highly recommended. In my case a Powerbank worked fine.

However the Blue PCB (V2.0/5V Compatible): Features an onboard voltage regulator, allowing it to be powered by 5V, which is convenient for Arduino interfacing


Network & Communication Testing:

Before integrating the GSM module into the main project, we must verify its connection to the cellular network and its ability to transmit data. Open the Serial Monitor to view the module's status response (using AT commands like AT+CREG? and AT+CSQ).

#include <SoftwareSerial.h>


//Create software serial object to communicate with SIM800L
SoftwareSerial mySerial(3, 2); //SIM800L Tx & Rx is connected to Arduino #3 & #2


void setup()
{
//Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
Serial.begin(9600);
//Begin serial communication with Arduino and SIM800L
mySerial.begin(9600);


Serial.println("Initializing...");
delay(1000);


mySerial.println("AT"); //Once the handshake test is successful, it will back to OK
updateSerial();
mySerial.println("AT+CSQ"); //10-14: Fair signal. SMS sending might succeed but could still be inconsistent.
//15-19: Good signal. SMS sending should be reliable.
//20-31: Excellent signal. SMS sending should be very reliable.
updateSerial();
mySerial.println("AT+CCID"); //Read SIM information to confirm whether the SIM is plugged
updateSerial();
mySerial.println("AT+CREG?"); //Check whether it has registered in the network
updateSerial();
}


void loop()
{
updateSerial();
}


void updateSerial()
{
delay(500);
while (Serial.available())
{
mySerial.write(Serial.read());//Forward what Serial received to Software Serial Port
}
while(mySerial.available())
{
Serial.write(mySerial.read());//Forward what Software Serial received to Serial Port
}
}


//AT+CSQ – It checks ‘Signal Strength

//AT+CCID – It checks whether the SIM card is valid or not and sends the SIM card number.

//AT+CREG? – It checks whether you are registered to the network or not. 1 HOME NETWORK,,,5 ROAMIING

//AT+COPS? – Checks which network you are connected to.


SMS Send Test: Now that you have verified your GSM module we can go ahead to do a SMS send test. Upload the SMS Send Test Code to confirm the module can successfully dispatch a text message to a specified phone number.

#include <SoftwareSerial.h>


//Create software serial object to communicate with SIM800L
SoftwareSerial mySerial(3, 2); //SIM800L Tx & Rx is connected to Arduino #3 & #2


void setup()
{
//Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
Serial.begin(9600);
//Begin serial communication with Arduino and SIM800L
mySerial.begin(9600);


Serial.println("Initializing...");
delay(1000);


mySerial.println("AT"); //Once the handshake test is successful, it will back to OK
updateSerial();


mySerial.println("AT+CMGF=1"); // Configuring TEXT mode
updateSerial();
mySerial.println("AT+CMGS=\"+ZZxxxxxxxxxxx\"");//change ZZ with country code and xxxxxxxxxxx with phone number to sms
updateSerial();
mySerial.print("GCS TEST FROM GLOVE"); //text content
updateSerial();
mySerial.write(26);
}


void loop()
{
}


void updateSerial()
{
delay(500);
while (Serial.available())
{
mySerial.write(Serial.read());//Forward what Serial received to Software Serial Port
}
while(mySerial.available())
{
Serial.write(mySerial.read());//Forward what Software Serial received to Serial Port
}
}


SMS Receive Test: Upload the SMS Receive Test Code to ensure the module can receive incoming messages, which is useful for debugging or future bi-directional features.

#include <SoftwareSerial.h>


//Create software serial object to communicate with SIM800L
SoftwareSerial mySerial(3, 2); //SIM800L Tx & Rx is connected to Arduino #3 & #2


void setup()
{
//Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
Serial.begin(9600);
//Begin serial communication with Arduino and SIM800L
mySerial.begin(9600);


Serial.println("Initializing...");
delay(1000);


mySerial.println("AT"); //Once the handshake test is successful, it will back to OK
updateSerial();
mySerial.println("AT+CMGF=1"); // Configuring TEXT mode
updateSerial();
mySerial.println("AT+CNMI=1,2,0,0,0"); // Decides how newly arrived SMS messages should be handled
updateSerial();
}


void loop()
{
updateSerial();
}


void updateSerial()
{
delay(500);
while (Serial.available())
{
mySerial.write(Serial.read());//Forward what Serial received to Software Serial Port
}
while(mySerial.available())
{
Serial.write(mySerial.read());//Forward what Software Serial received to Serial Port
}
}


To ensure your Gesture Communication System operates reliably, follow these brief pre-flight checks:

  1. SIM Credit: Ensure both sender and receiver SIM cards have enough airtime or SMS bundles.
  2. Reliable Network: Use a provider with the strongest, most stable coverage in your specific area.
  3. Signal Strength: Use the Network Health Check code to confirm an AT+CSQ value between 15 and 31. Weak signals can cause message failure or system resets.


Heart-rate Sensor Setup

IMG-20260204-WA0016(1).jpg

In this stage of the project, we integrate the Pulse Sensor and the OLED Display into the Communication Mode (Arduino Nano). This subsystem provides immediate visual feedback of the wearer’s heart rate—a critical safety feature of the Gesture Glove.

1. The Hardware Hookup

The Arduino Nano uses I2C communication for the OLED and a high-resolution Analog input for the pulse sensor. Follow these connections

For the OLED Display:

  1. VCC connect to 5V
  2. GND connect to GND
  3. SCL connect to A5
  4. SDA connect to A4

For the Pulse Sensor:

  1. VCC connect to 5V (or 3.3V for a cleaner signal)
  2. GND connect to GND
  3. Signal (S) connect to A7


Pro Tip: If the pulse sensor readings are too noisy, try connecting the sensor's VCC to the 3.3V pin on the Nano instead of 5V for a cleaner signal.


2. Calibration & Code

Heart rate sensors are sensitive to pressure and ambient light. This code includes a Pulse Detection Algorithm that calculates the time between beats to provide a stable Beats Per Minute (BPM) reading while drawing a live waveform.

Code;

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>

Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);

#define sensor A7
#define THRESHOLD 550 // Adjust this based on Serial Monitor readings

int x = 0;
int lastX = 0, lastY = 60;
int BPM = 0;
unsigned long lastBeatTime = 0;
bool pulseDetected = false;

void setup() {
Serial.begin(9600);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
for(;;); // Halt if screen is not found
}
display.clearDisplay();
}

void loop() {
int rawValue = analogRead(sensor);
// 1. Calculate BPM
if (rawValue > THRESHOLD && !pulseDetected) {
unsigned long currentMillis = millis();
unsigned long duration = currentMillis - lastBeatTime;
if (duration > 400) { // Filter out noise (max 150 BPM)
BPM = 60000 / duration;
lastBeatTime = currentMillis;
pulseDetected = true;
}
} else if (rawValue < THRESHOLD) {
pulseDetected = false;
}

// 2. Draw Waveform
int y = map(rawValue, 0, 1023, 63, 20); // Scale to screen height
if (x > 128) {
x = 0; lastX = 0;
display.clearDisplay();
}
display.drawLine(lastX, lastY, x, y, WHITE);
lastX = x; lastY = y;
x++;

// 3. Update Text Area
display.fillRect(0, 0, 128, 18, BLACK); // Clear top bar
display.setCursor(0, 0);
display.setTextSize(2);
display.setTextColor(WHITE);
display.print("BPM: ");
display.print(BPM);

display.display();
}

3. Testing & Validation

  1. Calibration: Open the Serial Plotter in the Arduino IDE. If the line doesn't "jump" when you press your finger on the sensor, adjust the THRESHOLD value in the code.
  2. Placement: Secure the sensor to your fingertip or earlobe using the provided strap. Don't press too hard, as it can cut off blood flow and stop the reading.
  3. Observation: You should see a "live" EKG-style wave moving across the OLED, with the BPM number updating every time a beat is detected.

Sanity Check: If the BPM jumps wildly (e.g., 20, then 150, then 80), the sensor is likely picking up "noise" from your movement. Keep your hand still during the test.


For more info on heart-rate sensor>>>https://www.hackster.io/rajeshjiet/pulse-rate-bpm-monitor-using-arduino-pulse-sensor-46d599

Testing Gesture-to-SMS

IMG-20260204-WA0002.jpg
IMG-20260209-WA0015.jpg

Now lets combine Flex sensors, OLED and GSM. This mini-project tests if a specific gesture can send a text. In this test we only focused on three (3) flex sensors, you can choose to expand to five.

Gesture to SMS Mini-Project Update the PHONE_NUMBER variable before uploading.

Code:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SoftwareSerial.h>


Adafruit_SSD1306 display(128, 64, &Wire, -1);


// Pin definitions
const int ringPin = A1;
const int indexPin = A3;
const int middlePin = A2;


// Thresholds for gesture detection, use the thresholds you got from the threshold test
const int thumbThreshold = 80;
const int indexThreshold = 80;
const int middleThreshold = 80;


// Software Serial for GSM module
SoftwareSerial GSM(3, 2); // RX, TX
#define PHONE_NUMBER "+ZZxxxxxxxxx" // Phone number to send the text to


bool isCommunicationMode = true;
unsigned long lastGestureTime = 0;


void setup() {
Serial.begin(9600);
GSM.begin(9600);


pinMode(ringPin, INPUT);
pinMode(indexPin, INPUT);
pinMode(middlePin, INPUT);


if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.print("CALIBERATING...");
display.display();
delay(2000);
display.clearDisplay();
}


void loop() {
int ringValue = analogRead(ringPin);
int indexValue = analogRead(indexPin);
int middleValue = analogRead(middlePin);


display.clearDisplay();
display.setCursor(0,0);


if (isCommunicationMode) {
handleCommunicationMode(ringValue, indexValue, middleValue);
if (isGestureDetected(ringValue, indexValue, middleValue)) {
lastGestureTime = millis(); // Update last gesture time
}
}


display.display();
delay(500);
}


void handleCommunicationMode(int thumbValue, int indexValue, int middleValue) {
if (thumbValue < thumbThreshold && indexValue >= indexThreshold && middleValue >= middleThreshold) {
display.print("I need my medicine");
sendSMS("I need my medicine");
} else if (indexValue < indexThreshold && thumbValue >= thumbThreshold && middleValue >= middleThreshold) {
display.print("I want water");
sendSMS("I want water");
} else if (middleValue < middleThreshold && thumbValue >= thumbThreshold && indexValue >= indexThreshold) {
display.print("I need to use the bathroom");
sendSMS("I need to use the bathroom");
} else if (thumbValue < thumbThreshold && indexValue < indexThreshold && middleValue >= middleThreshold) {
display.print("I am cold");
sendSMS("I am cold");
} else if (thumbValue < thumbThreshold && middleValue < middleThreshold && indexValue >= indexThreshold) {
display.print("My head hurts");
sendSMS("My head hurts");
} else if (indexValue < indexThreshold && middleValue < middleThreshold && thumbValue >= thumbThreshold) {
display.print("I am hungry");
sendSMS("I am hungry");
} else {
display.print("GESTURE COMMUNICATION SYSTEM");
}
}


bool isGestureDetected(int thumbValue, int indexValue, int middleValue) {
return (thumbValue < thumbThreshold && indexValue < indexThreshold && middleValue < middleThreshold);
}


void sendSMS(String message) {
GSM.println("AT+CMGF=1"); // Set the GSM module to text mode
delay(100);
GSM.print("AT+CMGS=\"");
GSM.print(PHONE_NUMBER);
GSM.println("\"");
delay(100);
GSM.println(message);
GSM.println((char)26); // End SMS command
delay(100);
}

Bluetooth Setup

To set up the wireless link for the "Brain" of your system, you need to pair the two Bluetooth modules so they connect automatically every time you power them on.

Follow the process highlighted in the video here>>>https://youtu.be/BXXAcFOTnBo?si=ySEG3oh7lW75uPdy


HC-05 Master & Slave Configuration

Before building the glove, we must "bind" the two modules. In this setup, the Arduino Nano (Master) will send commands, and the Arduino Uno (Slave) will receive them.

1. Enter AT Mode

To configure the modules, they must be in Command Mode (AT Mode).

Wiring:

  1. VCC5V
  2. GNDGND
  3. TXPin 10
  4. RXPin 11

The Trick: Hold the small button on the HC-05 module while plugging in the USB cable.

Confirmation: The onboard LED should blink slowly (once every 2 seconds). If it blinks fast, it is not in AT mode.


2. Configure the Slave (Arduino Uno Receiver)

Pass-Through Code;

#include <SoftwareSerial.h>

// Note: Connect TX to Pin 10 and RX to Pin 11 for this step
SoftwareSerial BTSerial(10, 11);

void setup() {
Serial.begin(9600);
Serial.println("Bluetooth AT Mode Ready. Set Serial Monitor to 'Both NL & CR' and 9600 baud.");

// Most HC-05 modules use 38400 for AT Mode
BTSerial.begin(38400);
}

void loop() {
// Read from HC-05 and send to Serial Monitor
if (BTSerial.available())
Serial.write(BTSerial.read());

// Read from Serial Monitor and send to HC-05
if (Serial.available())
BTSerial.write(Serial.read());
}

Upload a blank "Pass-Through" code to the Uno and open the Serial Monitor (Set to 9600 baud and Both NL & CR). Enter these commands:

  1. AT → Response: OK.
  2. AT+ROLE= 0 → This sets module as Slave.
  3. AT+UART= 38400,0,0 → This sets the communication speed.
  4. AT+ADDR? → Returns the unique address (e.g., 98d3:31:f9882). Copy this address.


3. Configure the Master (Arduino Nano Glove)

Swap the modules and enter these commands for the Master, Upload a blank "Pass-Through" code to the nano and open the Serial Monitor (Set to 9600 baud and Both NL & CR). Enter these commands::

  1. AT+ROLE=1 → Sets module as Master.
  2. AT+CMODE=0 → Connects only to a specific address.
  3. AT+BIND=98d3,31,f9882 → Replace the colons in your Slave address with commas. This "marries" the two modules.

ALTERNATIVELY

Unplug the Arduino USB and remove the Slave module. Insert HC-05 Master into the exact same wires.

Hold the button on the HC-05 and plug in the Arduino USB. The LED should blink slowly.

In the Serial Monitor, enter the Master commands:

  1. AT+ORGL (Reset)
  2. AT+ROLE=1 (Set Master)
  3. AT+UART=38400,0,0
  4. AT+CMODE=0
  5. AT+BIND=98d3,31,f9882 (Use the address from Step 2 with commas).


Wireless Connectivity Test

Now, let's verify they are talking. Note that the Slave (Uno) uses different pins to stay clear of the AC/DC control circuits we will add later.

Master Test Code (Arduino Nano)

  1. Pins: TX → D10 | RX → D11

Code;

#include <SoftwareSerial.h>
SoftwareSerial BTSerial(10, 11); // RX, TX on Nano

void setup() {
BTSerial.begin(38400);
}

void loop() {
BTSerial.println("TEST_SIGNAL"); // Send a heartbeat signal
delay(1000);
}

Slave Test Code (Arduino Uno)

  1. Pins: TX → D2 | RX → D3

Code;

#include <SoftwareSerial.h>
SoftwareSerial BTSerial(2, 3); // RX, TX on Uno

void setup() {
Serial.begin(9600);
BTSerial.begin(38400);
Serial.println("Waiting for Master...");
}

void loop() {
if (BTSerial.available()) {
String data = BTSerial.readStringUntil('\n');
Serial.print("Received: ");
Serial.println(data); // If you see "TEST_SIGNAL", your pairing is perfect!
}
}


Verification: Power both Arduinos. The LEDs on both Bluetooth modules should change from a slow/fast blink to a synchronized double-blink every few seconds. This means they are officially connected!


After you can mount the Master HC05 together with the Flex Sensors, Sim800l, OLED and Arduino Nano, Next we would look at the Autiomation mode setup and together with the Slave HC05, Relays, home appliance .etc

Automation Mode

Screenshot 2026-02-05 11.07.05 PM.png
Screenshot 2026-02-06 11.35.38 AM.png
IMG-20260204-WA0090.jpg
IMG-20260204-WA0011.jpg


This phase builds the separate "Home Automation Box" using an Arduino Uno. This unit receives Bluetooth signals from the glove to turn appliances on or off.

⚠️ WARNING: High Voltage Safety When wiring the Relay Module to AC bulbs or sockets, ensure the main power is OFF. If you are not experienced with AC mains, ask a qualified instructor for help or stick to DC loads (like LED strips or fans).

System Overview

This project phase consists of:

  1. Arduino Uno (controller)
  2. Two-channel relay module (AC socket and light)
  3. Single-channel relay module (12V DC fan)
  4. AC-to-DC converter (12V output)
  5. Buck converter (Arduino power)
  6. A barrel jack and electrical wires
  7. AC socket, AC light bulb, and 12V DC fan

1. Create the Common Live Junction (AC Input Side)

  1. Take the live (L) wire from the AC mains supply.
  2. At a junction point, connect this live wire to:
  3. The live input terminal of the AC-to-DC converter
  4. One terminal of the light bulb
  5. A wire that feeds the COM terminals of the relays used to switch the light bulb and the socket

From this junction, only one wire is soldered to the AC-to-DC converter’s live input pad.

2. Create the Common Neutral Junction (AC Input Side)

  1. Take the neutral (N) wire from the AC mains supply.
  2. Join it at a common neutral junction together with:
  3. The neutral wire of the light bulb
  4. The neutral terminal of the socket
  5. The neutral input terminal of the AC-to-DC converter

Again, only one neutral wire goes from this junction to the AC-to-DC converter’s neutral input pad.

3. Wiring the Light Bulb Through Its Relay

  1. Connect the mains live junction to the COM terminal of the relay assigned to the light bulb.
  2. Connect the NO (Normally Open) terminal of this relay to the remaining live terminal of the light bulb.
  3. The neutral side of the light bulb remains permanently connected to the common neutral junction.

📌 Result: The relay switches only the live line, turning the light ON and OFF safely.

4. Wiring the Socket Through Its Relay

  1. Connect the mains live junction to the COM terminal of the socket’s relay.
  2. Connect the NO terminal of this relay to the live terminal of the socket.
  3. Connect the neutral terminal of the socket directly to the common neutral junction.

📌 Result: The socket receives power only when its relay is energized.

5. AC-to-DC Converter Output Connections

  1. From the output side of the AC-to-DC converter:
  2. Connect Output+ to:
  3. The COM terminal of the single-channel relay used for the 12 V DC fan
  4. The IN+ terminal of the buck converter
  5. Connect Output− to:
  6. The negative terminal of the 12 V DC fan
  7. The IN− terminal of the buck converter

6. Wiring the 12 V DC Fan Through the Single Relay

  1. Connect Output+ from the AC-to-DC converter to the COM terminal of the single-channel relay.
  2. Connect the NO terminal of this relay to the positive terminal of the 12 V DC fan.
  3. Connect the negative terminal of the fan directly to Output− of the AC-to-DC converter.

📌 Result: The relay switches the positive DC line to control the fan.

7. Buck Converter and Arduino Power Supply

  1. From the output side of the AC-to-DC converter:
  2. Connect Output+ to IN+ of the buck converter
  3. Connect Output− to IN− of the buck converter
  4. Using a multimeter, adjust the buck converter output to 7–9 V DC.
  5. From the output of the buck converter:
  6. Connect OUT+ to the positive wire of the barrel jack
  7. Connect OUT− to the negative wire of the barrel jack
  8. Plug the barrel jack into the Arduino UNO.

📌 This safely powers the Arduino UNO from the mains supply.



Hardware Sanity Test (Automation Mode)

Before moving into wireless control, we must perform a Hardware Sanity Test. This ensures that the Arduino Uno can physically trigger each relay and that your wiring—from the high-voltage AC lines to the DC fan—is perfectly secure. We will use a "Blink Test" logic to cycle through each load.

⚠️ Safety First!

Warning: This step involves Live AC Voltage (110V/220V).

  1. Ensure all AC connections (Live and Neutral) are properly insulated and housed.
  2. Verify that your AC-to-DC converter is outputting a stable voltage before connecting the Arduino.
  3. Never touch the relay board or exposed wires while the system is plugged into the wall outlet.

The Hardware Sanity Code

This script sequence triggers the Socket, the Light Bulb, and the DC Fan one after another. Note that most relay modules are Active-Low, meaning LOW turns the relay ON and HIGH turns it OFF.


Code;

const int socketRelayPin = 8;
const int lightBulbRelayPin = 7;
const int dcFanRelayPin = 9;

const unsigned long blinkInterval = 3000; // 3 second delay

void setup() {
Serial.begin(9600); // Initialize serial monitor for debugging
pinMode(socketRelayPin, OUTPUT);
pinMode(lightBulbRelayPin, OUTPUT);
pinMode(dcFanRelayPin, OUTPUT);

// Initialize all relays to OFF (High)
digitalWrite(socketRelayPin, HIGH);
digitalWrite(lightBulbRelayPin, HIGH);
digitalWrite(dcFanRelayPin, HIGH);
}

void loop() {
// Test Socket Relay
Serial.println("Testing: Socket ON");
digitalWrite(socketRelayPin, LOW);
delay(blinkInterval);
digitalWrite(socketRelayPin, HIGH);
Serial.println("Socket OFF");

// Test Light Bulb Relay
Serial.println("Testing: Light Bulb ON");
digitalWrite(lightBulbRelayPin, LOW);
delay(blinkInterval);
digitalWrite(lightBulbRelayPin, HIGH);
Serial.println("Light Bulb OFF");

// Test DC Fan Relay
Serial.println("Testing: DC Fan ON");
digitalWrite(dcFanRelayPin, LOW);
delay(blinkInterval);
digitalWrite(dcFanRelayPin, HIGH);
Serial.println("DC Fan OFF");

delay(2000); // Pause before restarting the cycle
}


Execution & Verification

  1. Upload the Code: Connect your Arduino Uno to your PC and upload the sketch above.
  2. Open Serial Monitor: Set the baud rate to 9600. You should see the status messages printing in real-time.
  3. Observe the Loads:
  4. The Socket (or whatever is plugged into it) should activate for 1 second.
  5. The Light Bulb should flash.
  6. The DC Fan should pulse on.
  7. Listen for the "Click": Even if your AC loads aren't plugged in yet, you should hear a distinct mechanical click from each relay as it switches.

Troubleshooting:

  1. No "Clicking": Check if the Relay VCC/GND pins are connected to the Arduino 5V/GND.
  2. Inverted Logic: If the light stays ON and only blinks OFF for a second, your relay may be wired to the NC (Normally Closed) terminal instead of the NO (Normally Open) terminal. Move your load wire to the NO terminal.


If it worked, great job! Now we can join all the forces together Captain Planet Stlye!!! GENZ should reseach who Captain Planet is;)

Bonus (Gesture-Controlled Home Automation)

IMG-20260206-WA0063.jpg

If you want to see the magic happen before finalizing the full glove code, this bonus step is for you! We will use the paired Bluetooth modules to create a "Remote Control Glove" prototype. In this version, bending individual fingers will toggle the Fan, Bulb, and Socket independently.

Note: You can skip this and go straight to the main project if you are ready for the full integration.

1. Hardware Setup

For this test, we only need three flex sensors on the Nano side and the full relay/LCD setup on the Uno side.

Master Side (Arduino Nano):

  1. Flex Sensors: Connect three flex sensors to A0 (Pinky), A1 (Index), and A2 (Middle). Use 10k resistors for the voltage dividers.
  2. Bluetooth HC-05 (Master): TX → D10, RX → D11.

Slave Side (Arduino Uno):

  1. Bluetooth HC-05 (Slave): TX → D2, RX → D3.
  2. Relays: Fan → D9, Bulb → D7, Socket → D8.
  3. I2C LCD: SDA → A4, SCL → A5.


2. The Master Code (Glove Side)

This code monitors your fingers. It uses a "toggle" logic—bend the finger once to turn a device ON, and bend it again to turn it OFF.

Remember to use your threshold value!

Code;

#include <SoftwareSerial.h>
SoftwareSerial BTSerial(10, 11); // RX, TX

// Pin assignments
const int pinkyPin = A0;
const int ringPin = A1;
const int middlePin = A2;

int pinkyState = LOW;
int ringState = LOW;
int middleState = LOW;

int prevPinky = HIGH;
int prevRing = HIGH;
int prevMiddle = HIGH;

void setup() {
Serial.begin(9600);
BTSerial.begin(38400);
}

void loop() {
int pinkyValue = analogRead(pinkyPin);
int ringValue = analogRead(ringPin);
int middleValue = analogRead(middlePin);

// Pinky controls Relay 1 (Fan) Replace 80 with your threshold
if (pinkyValue < 80) {
if (prevPinky == HIGH) {
pinkyState = !pinkyState;
BTSerial.println(pinkyState ? "Relay1 ON" : "Relay1 OFF");
}
prevPinky = LOW;
} else { prevPinky = HIGH; }

// Ring controls Relay 2 (Bulb) Replace 1000 with your threshold
if (ringValue < 100) {
if (prevRing == HIGH) {
ringState = !ringState;
BTSerial.println(ringState ? "Relay2 ON" : "Relay2 OFF");
}
prevRing = LOW;
} else { prevRing = HIGH; }

// Middle controls Relay 3 (Socket) Replace 100 with your threshold
if (middleValue < 100) {
if (prevMiddle == HIGH) {
middleState = !middleState;
BTSerial.println(middleState ? "Relay3 ON" : "Relay3 OFF");
}
prevMiddle = LOW;
} else { prevMiddle = HIGH; }

delay(100); // Debounce delay
}



3. The Slave Code (Receiver Side)

This code listens for commands and updates both the physical relays and the LCD screen status simultaneously.

Code;

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>

SoftwareSerial BTSerial(2, 3); // RX, TX

const int relay1Pin = 9; // Fan
const int relay2Pin = 7; // Bulb
const int relay3Pin = 8; // Socket

LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
BTSerial.begin(38400);
pinMode(relay1Pin, OUTPUT);
pinMode(relay2Pin, OUTPUT);
pinMode(relay3Pin, OUTPUT);

// Initialize Relays OFF (High)
digitalWrite(relay1Pin, HIGH);
digitalWrite(relay2Pin, HIGH);
digitalWrite(relay3Pin, HIGH);

lcd.begin(16, 2);
lcd.backlight();
lcd.setCursor(0, 0); lcd.print("FAN:OFF BULB:OFF");
lcd.setCursor(0, 1); lcd.print("SOCKET:OFF");
}

void loop() {
if (BTSerial.available()) {
String command = BTSerial.readStringUntil('\n');
command.trim();

// Handle Fan (Relay 1)
if (command == "Relay1 ON") {
digitalWrite(relay1Pin, LOW);
lcd.setCursor(0, 0); lcd.print("FAN:ON ");
}
else if (command == "Relay1 OFF") {
digitalWrite(relay1Pin, HIGH);
lcd.setCursor(0, 0); lcd.print("FAN:OFF ");
}

// Handle Bulb (Relay 2)
if (command == "Relay2 ON") {
digitalWrite(relay2Pin, LOW);
lcd.setCursor(8, 0); lcd.print("BULB:ON ");
}
else if (command == "Relay2 OFF") {
digitalWrite(relay2Pin, HIGH);
lcd.setCursor(8, 0); lcd.print("BULB:OFF ");
}

// Handle Socket (Relay 3)
if (command == "Relay3 ON") {
digitalWrite(relay3Pin, LOW);
lcd.setCursor(0, 1); lcd.print("SOCKET:ON ");
}
else if (command == "Relay3 OFF") {
digitalWrite(relay3Pin, HIGH);
lcd.setCursor(0, 1); lcd.print("SOCKET:OFF ");
}
}
}


What to Expect:

  1. Power both boards.
  2. Wait for the Bluetooth LEDs to show a steady "paired" double-blink.
  3. Bend your Pinky finger: The DC Fan should start spinning, and the LCD will update to "FAN:ON".
  4. Bend your Ring finger: The AC Light Bulb should turn on.
  5. Bend your Middle finger: The AC Socket relay will click.

This confirms your wireless automation link is 100% functional and ready for the final project integration!

Finale

IMG-20260204-WA0090(3).jpg
IMG-20260206-WA0074.jpg

We have reached the finish line!!! In this step, we merge all previous test codes into two final sketches: one for the Glove (Master) and one for the Automation Hub (Slave).


Final Checklist

  1. Sim Card: Ensure your SIM card has credit and is inserted correctly in the SIM800L, check mobile receiver mobile number.
  2. Power: The SIM800L and the Relays consume a lot of power. Ensure your external batteries are charged.
  3. Flex Sensors: If the glove isn't triggering, check the flexThreshold in the code (currently set to 80). You may need to increase this number if your sensors are less sensitive.
  4. Baud Rate: The HC-05 Bluetooth module must be configured to 38400 baud in AT mode for it to communicate with this code.
  5. Prerequisites: Before uploading, ensure you have installed the following libraries in your Arduino IDE:
  6. Adafruit_GFX
  7. Adafruit_SSD1306
  8. LiquidCrystal_I2C


The "Brain" (Arduino Nano Master)

This code is the operating system for your glove. It manages three distinct modes:

  1. Communication Mode: Detects specific finger bends to send pre-set SMS alerts.
  2. Automation Mode: Uses the Thumb to toggle into this mode, where finger bends turn your fan, light, and socket on/off wirelessly.
  3. BPM Mode (Health): Automatically activates if you are inactive for 15 seconds. It monitors your heart rate and sends an emergency SMS if it detects abnormal activity.


WHAT TO EXPECT

On Startup: The OLED screen will display "Gesture Communication System". The glove starts in Communication Mode by default.

Switching Modes: The Thumb (A6) is your "Mode Switch" button.

  1. If you bend the Thumb, the system toggles between Communication Mode and Automation Mode.
  2. The screen will briefly say "Automation Mode Activated" or "Communication Mode Activated" to tell you where you are.
  3. Sleep/Health Mode: If you do not move any fingers for 15 seconds, the system assumes you are resting and automatically enters BPM (Health) Mode.

Mode I: Communication Mode (Default)

Goal: Send SMS messages and display text on the screen for speech assistance. Visual: The screen shows "Gesture Communication System".

Gestures (What happens when you bend):

  1. Pinky Only:
  2. Screen: Displays "I need my medicine"
  3. Action: Sends SMS "I need my medicine" to the contact number.
  4. Ring Finger Only:
  5. Screen: Displays "I want water"
  6. Action: Sends SMS "I want water".
  7. Middle Finger Only:
  8. Screen: Displays "I am cold"
  9. Action: Sends SMS "I am cold".
  10. Index Finger Only:
  11. Screen: Displays "My head hurts"
  12. Action: Sends SMS "My head hurts".
  13. Pinky + Ring (Together):
  14. Screen: Displays "I am hungry"
  15. Action: Sends SMS "I am hungry".
  16. Pinky + Ring + Middle (Together):
  17. Screen: Displays "Need to use the bathroom"
  18. Action: Sends SMS "Need to use the bathroom".
Note: The code prioritizes "Combined Bends" first. If you bend Pinky, Ring, and Middle, it will only send the bathroom message, not the individual messages.


Mode II: Automation Mode

Goal: Control home appliances (Fan, Light, Socket) wirelessly via Bluetooth. Visual: The screen shows "Automation Mode Activated".

Gestures (Toggle Control):

  1. Pinky: Acts as a switch for the Fan.
  2. Bend once: Fan turns ON.
  3. Bend again: Fan turns OFF.
  4. Ring Finger: Acts as a switch for the Light Bulb.
  5. Bend once: Light turns ON.
  6. Bend again: Light turns OFF.
  7. Middle Finger: Acts as a switch for the Socket.
  8. Bend once: Socket turns ON.
  9. Bend again: Socket turns OFF.


Mode III: BPM (Health) Mode

Goal: Monitor heart rate when the user is inactive/sleeping. Trigger: This happens automatically if you don't move your hand for 15 seconds.

What to expect:

  1. Screen: Displays "AVERAGE BPM" and a number (e.g., 75).
  2. Normal Behavior: It will continuously update the screen with your heart rate every few seconds.
  3. Emergency Trigger:
  4. If the BPM drops below 60 or goes above 100:
  5. Screen: Flashes "Alert! Abnormal BPM".
  6. Action: Sends an EMERGENCY SMS: "Emergency Alert: Patient's BPM is below/above normal at [value]."
  7. How to Exit: To wake the glove up and go back to normal Communication Mode, simply bend any finger


Upload this code to your Arduino Nano:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SoftwareSerial.h>


// OLED setup
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


// SIM800L setup
SoftwareSerial SIM800L(3, 2); // RX, TX


// Mobile Contact Number Enter yours here
const char* ContactNumber = "+ZZxxxxxxxxxxx";


// HC05 Bluetooth setup
SoftwareSerial BTSerial(10, 11); // RX, TX


// Flex sensor pins
#define THUMB_PIN A6
#define INDEX_PIN A3
#define MIDDLE_PIN A2
#define RING_PIN A1
#define PINKY_PIN A0


// Heart Rate Sensor Pin
const int heartRatePin = A7; // Pin connected to heart rate sensor


// Thresholds change with your recorded threshold values from threshold test
const int flexThreshold = 80;
const unsigned long inactivityTimeout = 15000; // 15 seconds


// Heart Rate Sensor Constants
const int minValue = 620; // Minimum sensor value without finger
const int maxValue = 1000; // Maximum sensor value with finger
const int minBPM = 60; // Minimum BPM value
const int maxBPM = 100; // Maximum BPM value
const int numReadings = 20; // Number of readings to average


// Mode Enumeration
enum Mode {
COMMUNICATION,
AUTOMATION,
BPM
};


Mode currentMode = COMMUNICATION;
Mode previousMode = COMMUNICATION;


// Inactivity Timer
unsigned long lastActivityTime = 0;


// BPM Variables
int readings[numReadings]; // Array to store sensor readings
int readIndex = 0; // Current index in the readings array
int total = 0; // Sum of readings
int averageBPM = 0; // Calculated average BPM
bool recording = true; // Flag to indicate if we are still recording


// Flex Sensor State Variables
bool prevFlexPinky = HIGH;
bool flexPinkyState = false;
bool prevFlexRing = HIGH;
bool flexRingState = false;
bool prevFlexMiddle = HIGH;
bool flexMiddleState = false;


// Debounce Timers
unsigned long lastToggleTime = 0;
const unsigned long debounceDelay = 2000; // 2 seconds debounce


void displayMessage(const __FlashStringHelper *message, unsigned long duration = 0);
void handleCommunicationMode(); // Function prototype
void handleAutomationMode(); // Function prototype
void handleBPMMode(); // Function prototype
void initializeBPM(); // Function prototype
void exitBPMMode(); // Function prototype
void toggleMode(); // Function prototype
void displayMode(); // Function prototype
void sendMessage(const __FlashStringHelper* message); // Function prototype
void displayDefaultMessage(); // Function prototype
void displayBPM(int BPM); // Function prototype
void displayAbnormalBPMAlert(); // Function prototype
void sendEmergencySMS(int BPM); // Function prototype


void setup() {
Serial.begin(9600);


// Initialize OLED display
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Use I2C address 0x3C
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Infinite loop if display not found
}
display.clearDisplay();
// Width calculation for "GC" to center it on OLED
int gestureWidth = 6 * 21; // Approximate width for "GC" at text size 1
display.setCursor((SCREEN_WIDTH - gestureWidth) / 2, 0);
display.println(F("Gesture Communication"));


// Adjust the width calculation for "System" to center it properly
int systemWidth = 6 * 6; // Approximate width for "System" at text size 1
display.setCursor((SCREEN_WIDTH - systemWidth) / 2, 20); // Center "System" text
display.println(F("System"));
display.display();


// SIM800L initialization
SIM800L.begin(9600);


// Bluetooth module initialization
BTSerial.begin(38400);


// Initialize BPM Variables
for (int i = 0; i < numReadings; i++) {
readings[i] = 0;
}
total = 0;
readIndex = 0;
averageBPM = 0;
recording = true;


lastActivityTime = millis(); // Initialize last activity time
}


void loop() {
// Read flex sensors
bool anyFingerBent = false;
if (analogRead(THUMB_PIN) < flexThreshold ||
analogRead(INDEX_PIN) < flexThreshold ||
analogRead(MIDDLE_PIN) < flexThreshold ||
analogRead(RING_PIN) < flexThreshold ||
analogRead(PINKY_PIN) < flexThreshold) {
anyFingerBent = true;
lastActivityTime = millis(); // Reset inactivity timer
}


// Handle Mode Switching based on Inactivity
if (millis() - lastActivityTime >= inactivityTimeout && currentMode != BPM) {
previousMode = currentMode;
currentMode = BPM;
displayMessage(F("Entering BPM Mode..."));
initializeBPM();
}


// Handle BPM Mode in a while loop
if (currentMode == BPM) {
// Keep running BPM mode until a finger is bent
while (!anyFingerBent) {
handleBPMMode(); // Continue handling BPM


// Check for any bent finger to exit BPM mode
if (analogRead(THUMB_PIN) < flexThreshold ||
analogRead(INDEX_PIN) < flexThreshold ||
analogRead(MIDDLE_PIN) < flexThreshold ||
analogRead(RING_PIN) < flexThreshold ||
analogRead(PINKY_PIN) < flexThreshold) {
anyFingerBent = true;
}


delay(100); // Small delay to prevent spamming sensor reads
}


// Exit BPM Mode if a finger is bent
exitBPMMode();
}


// Handle Communication or Automation Mode
else {
if (currentMode == COMMUNICATION) {
handleCommunicationMode();
} else if (currentMode == AUTOMATION) {
handleAutomationMode();
}


// Check for mode toggle via thumb bend
if (analogRead(THUMB_PIN) < flexThreshold) {
if (millis() - lastToggleTime > debounceDelay) { // 2-second debounce
toggleMode();
lastToggleTime = millis();
}
}
}


delay(100); // Main loop delay
}


// Function to toggle between Communication and Automation modes
void toggleMode() {
if (currentMode == COMMUNICATION) {
currentMode = AUTOMATION;
} else {
currentMode = COMMUNICATION;
}
displayMode();
}


// Function to display messages on OLED with optional duration
void displayMessage(const __FlashStringHelper *message, unsigned long duration = 0) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.println(message);
display.display();


if (duration > 0) {
delay(duration);
}
}


// Function to display the current mode
void displayMode() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);


if (currentMode == COMMUNICATION) {
display.setCursor(0, 0);
display.println(F(" Communication Mode"));
display.setCursor((SCREEN_WIDTH - 60) / 2, 20); // Center "Activated" text
display.println(F("Activated"));
display.display();


// Wait for 2 seconds before switching to default message
delay(2000);
displayDefaultMessage();


} else if (currentMode == AUTOMATION) {
display.setCursor(0, 0);
display.println(F(" Automation Mode"));
display.setCursor((SCREEN_WIDTH - 60) / 2, 20); // Center "Activated" text
display.println(F("Activated"));
display.display();
}
}


// Communication Mode Handler
void handleCommunicationMode() {
int pinkyValue = analogRead(PINKY_PIN);
int ringValue = analogRead(RING_PIN);
int middleValue = analogRead(MIDDLE_PIN);
int indexValue = analogRead(INDEX_PIN);


bool messageDisplayed = false;


// Combined bends
if (pinkyValue < flexThreshold && ringValue < flexThreshold && middleValue < flexThreshold) {
displayMessage(F("Need to use the bathroom"), 1500); // Display for 1.5 seconds
sendMessage(F("Need to use the bathroom"));
messageDisplayed = true;
}
else if (pinkyValue < flexThreshold && ringValue < flexThreshold) {
displayMessage(F("I am hungry"), 1500); // Display for 1.5 seconds
sendMessage(F("I am hungry"));
messageDisplayed = true;
}
// Individual bends
else if (pinkyValue < flexThreshold) {
displayMessage(F("I need my medicine"), 1500); // Display for 1.5 seconds
sendMessage(F("I need my medicine"));
messageDisplayed = true;
}
else if (ringValue < flexThreshold) {
displayMessage(F("I want water"), 1500); // Display for 1.5 seconds
sendMessage(F("I want water"));
messageDisplayed = true;
}
else if (middleValue < flexThreshold) {
displayMessage(F("I am cold"), 1500); // Display for 1.5 seconds
sendMessage(F("I am cold"));
messageDisplayed = true;
}
else if (indexValue < flexThreshold) {
displayMessage(F("My head hurts"), 1500); // Display for 1.5 seconds
sendMessage(F("My head hurts"));
messageDisplayed = true;
}


// If a message was displayed, revert back to default screen
if (messageDisplayed) {
displayDefaultMessage();
} else {
displayDefaultMessage();
}
}


// Automation Mode Handler
void handleAutomationMode() {
int pinkyValue = analogRead(PINKY_PIN);
int ringValue = analogRead(RING_PIN);
int middleValue = analogRead(MIDDLE_PIN);


// Handle Pinky Flex
if (pinkyValue < flexThreshold) {
if (prevFlexPinky == HIGH) {
flexPinkyState = !flexPinkyState;
BTSerial.println(flexPinkyState ? "Relay1 ON" : "Relay1 OFF");
displayMessage(flexPinkyState ? F("DC-Fan: ON") : F("DC-fan: OFF"), 1500); // Display for 1.5 seconds
lastActivityTime = millis(); // Reset inactivity timer
}
prevFlexPinky = LOW;
} else {
prevFlexPinky = HIGH;
}


// Handle Ring Flex
if (ringValue < flexThreshold) {
if (prevFlexRing == HIGH) {
flexRingState = !flexRingState;
BTSerial.println(flexRingState ? "Relay2 ON" : "Relay2 OFF");
displayMessage(flexRingState ? F("Light: ON") : F("Light: OFF"), 1500); // Display for 1.5 seconds
lastActivityTime = millis(); // Reset inactivity timer
}
prevFlexRing = LOW;
} else {
prevFlexRing = HIGH;
}


// Handle Middle Flex
if (middleValue < flexThreshold) {
if (prevFlexMiddle == HIGH) {
flexMiddleState = !flexMiddleState;
BTSerial.println(flexMiddleState ? "Relay3 ON" : "Relay3 OFF");
displayMessage(flexMiddleState ? F("Socket: ON") : F("Socket: OFF"), 1500); // Display for 1.5 seconds
lastActivityTime = millis(); // Reset inactivity timer
}
prevFlexMiddle = LOW;
} else {
prevFlexMiddle = HIGH;
}
}


// Function to handle BPM Mode
void handleBPMMode() {
if (recording) {
// Collect 20 readings
total = 0;
for (int i = 0; i < numReadings; i++) {
readings[i] = analogRead(heartRatePin);
total += readings[i];
delay(50); // Small delay between readings
}
averageBPM = map(total / numReadings, minValue, maxValue, minBPM, maxBPM);


// Check for abnormal BPM
if (averageBPM < 60 || averageBPM > 100) {
displayAbnormalBPMAlert();
sendEmergencySMS(averageBPM);
} else {
displayBPM(averageBPM);
delay(5000); // Display average BPM for 5 seconds
}
recording = true; // Continue recording
}
}


// Function to display BPM
void displayBPM(int BPM) {
display.clearDisplay();


// Set the text size to 1.5 for "AVERAGE BPM"
display.setTextSize(1.5);
display.setTextColor(WHITE);


int textWidth = 6 * 12; // Approximate width for "AVERAGE BPM" at text size 1.5
display.setCursor((SCREEN_WIDTH - textWidth) / 2, 0); // Centered horizontally
display.println(F("AVERAGE BPM"));


// Set the text size to 3 for the BPM value
display.setTextSize(3);


// Calculate the width of the BPM value string
int bpmWidth = 18 * String(BPM).length(); // 18 pixels per character at text size 3
display.setCursor((SCREEN_WIDTH - bpmWidth) / 2, 20); // Adjust Y position as needed
display.println(BPM);


display.display();
}


// Function to display Abnormal BPM Alert
void displayAbnormalBPMAlert() {
display.clearDisplay();
display.setTextSize(2); // Set font size to 2 for "Alert!"
display.setTextColor(WHITE);


int alertWidth = 12 * 6; // Approximate width for "Alert!"
display.setCursor((SCREEN_WIDTH - alertWidth) / 2, 10);
display.println(F("Alert!"));


display.setTextSize(1); // Set font size to 1 for "Abnormal BPM"
int abnormalWidth = 6 * 12; // Approximate width for "Abnormal BPM" in font size 1
display.setCursor((SCREEN_WIDTH - abnormalWidth) / 2, 40); // Centering the text
display.println(F("Abnormal BPM"));


display.display();
delay(5000); // Display alert for 5 seconds
}


// Function to send Emergency SMS
void sendEmergencySMS(int BPM) {
SIM800L.println(F("AT+CMGF=1")); // Set SMS text mode
delay(100);
SIM800L.print(F("AT+CMGS=\"")); // Replace with the recipient's phone number
SIM800L.print(ContactNumber);
SIM800L.println(F("\""));
delay(100);


if (BPM < 60) {
SIM800L.print(F("Emergency Alert: Patient's BPM is below normal at "));
} else {
SIM800L.print(F("Emergency Alert: Patient's BPM is above normal at "));
}
SIM800L.print(BPM);
SIM800L.println(F("."));
SIM800L.write(26); // ASCII code for Ctrl+Z (End of message)
delay(1000); // Wait for SMS to send
}
void displayMessage(const __FlashStringHelper *line1, const __FlashStringHelper *line2, unsigned long duration = 0) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);


// Function below centers the display of both Communication and Automation System
// Calculate the width of each line
int line1Width = 6 * strlen_P((const char*)line1); // Width for line 1
int line2Width = 6 * strlen_P((const char*)line2); // Width for line 2


// Display line 1
display.setCursor((SCREEN_WIDTH - line1Width) / 2, SCREEN_HEIGHT / 2 - 10); // Adjust Y position for line 1
display.println(line1);


// Display line 2
display.setCursor((SCREEN_WIDTH - line2Width) / 2, SCREEN_HEIGHT / 2 + 10); // Adjust Y position for line 2
display.println(line2);


display.display();


if (duration > 0) {
delay(duration);
}
}


// Function to exit BPM Mode
void exitBPMMode() {
// Display mode activated message
if (previousMode == COMMUNICATION) {
displayMessage(F("Communication Mode"), F("Activated"), 2000); // Display for 2 seconds
} else if (previousMode == AUTOMATION) {
displayMessage(F("Automation Mode"), F("Activated"), 2000); // Display for 2 seconds
}


currentMode = previousMode;
recording = true; // Reset BPM recording flag
lastActivityTime = millis(); // Reset inactivity timer
}


// Function to display default message
void displayDefaultMessage() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);


// Adjust the width calculation for "GC" to center it properly
int gestureWidth = 6 * 21; // Approximate width for "GC" at text size 1
display.setCursor((SCREEN_WIDTH - gestureWidth) / 2, 0);
display.println(F("Gesture Communication"));


// Adjust the width calculation for "System" to center it properly
int systemWidth = 6 * 6; // Approximate width for "System" at text size 1
display.setCursor((SCREEN_WIDTH - systemWidth) / 2, 20); // Center "System" text
display.println(F("System"));


display.display();
}


// Function to send a message via SIM800L
void sendMessage(const __FlashStringHelper *message) {
SIM800L.println(F("AT+CMGF=1")); // Set SMS text mode
delay(100);
SIM800L.print(F("AT+CMGS=\"")); // Replace with the recipient's phone number
SIM800L.print(ContactNumber);
SIM800L.println(F("\""));
delay(100);
SIM800L.println(message); // Message to send
SIM800L.write(26); // ASCII code for Ctrl+Z (End of message)
delay(1000); // Wait for SMS to send
}


// Function to initialize BPM mode
void initializeBPM() {
// Clear previous readings
for (int i = 0; i < numReadings; i++) {
readings[i] = 0;
}
total = 0;
readIndex = 0;
recording = true;
delay(1000); // Brief delay before starting BPM readings
}



Part 2: The "Hub" (Arduino Uno Slave)

This code listens for Bluetooth signals from the glove. It doesn't need to "think"—it just waits for orders to turn the Fan (Relay 1), Bulb (Relay 2), or Socket (Relay 3) on and off.


Upload this code to your Arduino Uno:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>


SoftwareSerial BTSerial(2, 3); // RX, TX


const int relay1Pin = 9;
const int relay2Pin = 7;
const int relay3Pin = 8;


LiquidCrystal_I2C lcd(0x27, 16, 2); // Change the address if necessary


void setup() {
Serial.begin(9600);
BTSerial.begin(38400);


pinMode(relay1Pin, OUTPUT);
pinMode(relay2Pin, OUTPUT);
pinMode(relay3Pin, OUTPUT);


digitalWrite(relay1Pin, HIGH);
digitalWrite(relay2Pin, HIGH);
digitalWrite(relay3Pin, HIGH);


lcd.begin(16, 2); // Initialize the LCD with 16 columns and 2 rows
lcd.backlight();
lcd.clear();
updateLCD();
}


void updateLCD() {
lcd.setCursor(0, 0);
lcd.print("FAN:OFF BULB:OFF");
lcd.setCursor(0, 1);
lcd.print("SOCKET:OFF ");
}


void loop() {
if (BTSerial.available()) {
String command = BTSerial.readStringUntil('\n');
command.trim();


if (command == "Relay1 ON") {
digitalWrite(relay1Pin, LOW);
lcd.setCursor(0, 0);
lcd.print("FAN:ON ");
} else if (command == "Relay1 OFF") {
digitalWrite(relay1Pin, HIGH);
lcd.setCursor(0, 0);
lcd.print("FAN:OFF ");
}


if (command == "Relay2 ON") {
digitalWrite(relay2Pin, LOW);
lcd.setCursor(8, 0);
lcd.print("BULB:ON ");
} else if (command == "Relay2 OFF") {
digitalWrite(relay2Pin, HIGH);
lcd.setCursor(8, 0);
lcd.print("BULB:OFF ");
}


if (command == "Relay3 ON") {
digitalWrite(relay3Pin, LOW);
lcd.setCursor(0, 1);
lcd.print("SOCKET:ON ");
} else if (command == "Relay3 OFF") {
digitalWrite(relay3Pin, HIGH);
lcd.setCursor(0, 1);
lcd.print("SOCKET:OFF ");
}
}
}



Congratulations! You have now built a fully functional smart glove that can speak, control your home, and monitor your health.



DISCLAIMER: This project is a prototype designed for educational and research purposes only. It is not a certified medical device. The heart rate monitoring and emergency alert features should not be used as a substitute for professional medical equipment or emergency services. The author is not responsible for any health-related issues or system failures during use.





This Gesture Communication and Automation System was the result of our final year capstone research at the Accra Institute of Technology (AIT), School of Advanced Technologies, Engineering and Sciences (SATES).

The Project Team:

Emmanuel K. N. Anderson (B.Eng Electrical and Electronics Engineering)

Rikpossou Kafoui Augustine (B.Eng Electrical and Electronics Engineering)

Broni Ernest (B.Eng Computer Engineering)

Academic Supervision:

Mr. Rex Alphonse Bayor (Project Supervisor)

We designed this system to bridge the communication gap for individuals with sensory impairments, combining wearable technology with home automation and real-time health monitoring. This project stands as a testament to our undergraduate engineering journey and we hope you enjoyed building with us