Ideazero Designs
Published © MIT

Wearable Haptic Bands

A platform to convey enhanced information through multiple wearable haptic bands for a wide range of applications

IntermediateFull instructions provided12 hours267

Things used in this project

Hardware components

Seeed Studio XIAO ESP32S3 Sense
Seeed Studio XIAO ESP32S3 Sense
×1
Seeed Studio XIAO ESP32C3
Seeed Studio XIAO ESP32C3
×2
Blues Wireless Raspberry Pi Starter Kit
Blues Wireless Raspberry Pi Starter Kit
×1
PCBWay Custom PCB
PCBWay Custom PCB
×1
Grove Shield for Seeeduino XIAO - with embedded battery management chip
Seeed Studio Grove Shield for Seeeduino XIAO - with embedded battery management chip
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1
Polymer Lithium Ion Battery - 2200mAh 3.7V
Seeed Studio Polymer Lithium Ion Battery - 2200mAh 3.7V
×3
Gravity: Digital Vibration Sensor
DFRobot Gravity: Digital Vibration Sensor
×2

Software apps and online services

Arduino IDE
Arduino IDE
Blues Notehub.io
Blues Notehub.io
SMS Messaging API
Twilio SMS Messaging API
KiCad
KiCad

Hand tools and fabrication machines

Soldering Station, 110 V
Soldering Station, 110 V
3D Printer (generic)
3D Printer (generic)
10 Pc. Jumper Wire Kit, 5 cm Long
10 Pc. Jumper Wire Kit, 5 cm Long
Hot glue gun (generic)
Hot glue gun (generic)

Story

Read more

Custom parts and enclosures

Base_Bottom

Sketchfab still processing.

Base_LID

Sketchfab still processing.

Buttons

Sketchfab still processing.

Wearable_Bottom

Sketchfab still processing.

Wearable_LID

Sketchfab still processing.

Base_Buttons

Sketchfab still processing.

Schematics

Central Base Wiring

Wearable_Schematic

Code

Notecard SOS SMS TWILIO

C/C++
//NoteCard SMS twilio

#define BTN_PIN 9            // GPIO for the button
#define BTN_LONG_PRESS_MS 6000 // 6000ms = 6 seconds

#define FROM_PHONE_NUMBER "+16xxxxxxxx" // Replace with your Twilio registered number
#define TO_PHONE_NUMBER "+9xxxxxxxxx"   // Replace with the target phone number

unsigned long buttonPressTime = 0;
bool buttonPressed = false;

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

  // A short delay to allow everything to start up
  delay(6000);

  // Connect to the hub and set update period
  Serial1.println("{ \"req\": \"hub.set\", \"product\": \"com.example.example:my_project\", \"mode\":\"periodic\", \"minutes\": 2 }");
  delay(300); 
  while (Serial1.available()) { 
    Serial.write(Serial1.read()); 
  }

  // Enable the GPS
  Serial1.println("{ \"req\": \"card.location.mode\", \"mode\": \"periodic\", \"minutes\": 2 }");
  delay(300); 
  while (Serial1.available()) { 
    Serial.write(Serial1.read()); 
  }

  // Start periodically sending location to the hub
  Serial1.println("{ \"req\":\"card.location.track\", \"start\":true, \"heartbeat\":true, \"minutes\":20, \"file\":\"_track.qo\" }");
  delay(300); 
  while (Serial1.available()) { 
    Serial.write(Serial1.read()); 
  }

  // Initialize button pin
  pinMode(BTN_PIN, INPUT_PULLUP);
}

void loop() {
  // Button press detection
  if (digitalRead(BTN_PIN) == LOW) { // Button pressed
    if (!buttonPressed) {
      buttonPressed = true;
      buttonPressTime = millis();
    }
    // Check if the button is held for more than 6 seconds
    if (millis() - buttonPressTime > BTN_LONG_PRESS_MS) {
      sendSmsWithGps();
      buttonPressed = false;  // Reset the button press state
    }
  } else {
    // Reset button state when button is released
    buttonPressed = false;
  }
}

void sendSmsWithGps() {
  // Request GPS location
  Serial1.println("{ \"req\": \"card.location.track\" }");
  delay(2000); // Wait for GPS fix (adjust this delay if needed)

  // Retrieve GPS coordinates
  Serial1.println("{ \"req\": \"card.location\" }");
  delay(300);

  String gpsResponse = "";
  while (Serial1.available()) {
    gpsResponse += (char)Serial1.read();
  }

  // Extract lat/lon from the GPS response
  float lat = extractLat(gpsResponse);
  float lon = extractLon(gpsResponse);

  // Create a message with the GPS coordinates
  String message = "Emergency! Button pressed. GPS Coordinates: lat=" + String(lat, 6) + ", lon=" + String(lon, 6);

  // Send SMS via Twilio using Notecard
  sendNotificationWithSms(message);
}

void sendNotificationWithSms(String message) {
  // Create the SMS request
  String req = "{ \"req\": \"note.add\", \"file\": \"twilio.qo\", \"sync\": true, \"body\": { \"from\": \"" + String(FROM_PHONE_NUMBER) + "\", \"to\": \"" + String(TO_PHONE_NUMBER) + "\", \"message\": \"" + message + "\" } }";

  // Send the SMS
  Serial1.println(req);
  delay(300);
  while (Serial1.available()) {
    Serial.write(Serial1.read());
  }

  Serial.println("SMS with GPS coordinates sent.");
}

// Helper functions to extract lat/lon from GPS response
float extractLat(String gpsResponse) {
  int latIndex = gpsResponse.indexOf("\"lat\":");
  return gpsResponse.substring(latIndex + 6, gpsResponse.indexOf(",", latIndex)).toFloat();
}

float extractLon(String gpsResponse) {
  int lonIndex = gpsResponse.indexOf("\"lon\":");
  return gpsResponse.substring(lonIndex + 6, gpsResponse.indexOf(",", lonIndex)).toFloat();
}

Obstacle Avoid_Base

C/C++
#include <WiFi.h>
#include <esp_now.h>

#define ECHO_PIN 0    // Echo pin of HC-SR04
#define TRIG_PIN 1    // Trigger pin of HC-SR04
#define OBSTACLE_DISTANCE 1.5 // Distance threshold in meters (1.5 meters)

// Function to measure distance using the HC-SR04
float measureDistance() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH);
  float distance = duration * 0.0343 / 2;
  return distance;
}

// Function to broadcast data
void broadcast(const String &message) {
  uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  esp_now_peer_info_t peerInfo = {};
  memcpy(&peerInfo.peer_addr, broadcastAddress, 6);

  if (!esp_now_is_peer_exist(broadcastAddress)) {
    esp_now_add_peer(&peerInfo);
  }

  esp_err_t result = esp_now_send(broadcastAddress, (const uint8_t *)message.c_str(), message.length());

  if (result == ESP_OK) {
    Serial.println("Broadcast message success");
  } else {
    Serial.println("Broadcast message failed");
  }
}

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

  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);

  WiFi.mode(WIFI_STA);
  Serial.println("ESP-NOW Sender Setup");

  WiFi.disconnect();

  if (esp_now_init() == ESP_OK) {
    Serial.println("ESP-NOW Init Success");
  } else {
    Serial.println("ESP-NOW Init Failed");
    delay(3000);
    ESP.restart();
  }
}

void loop() {
  float distance = measureDistance();
  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println(" meters");

  // If obstacle is within 1.5 meters, send value 255 to all receivers
  if (distance <= OBSTACLE_DISTANCE) {
    Serial.println("Obstacle detected! Sending 255 to receivers.");
    broadcast("255");  // Sending 255 to all receivers
  }

  delay(1000);  // Check every 1 second
}

Obstacle_Avoid_Wearable

C/C++
#include <WiFi.h>
#include <esp_now.h>

#define ERM_PIN 10 // Pin where the ERM motor is connected

// Callback when data is received
void receiveCallback(const esp_now_recv_info *recvInfo, const uint8_t *data, int dataLen) {
  char buffer[ESP_NOW_MAX_DATA_LEN + 1];
  int msgLen = min(ESP_NOW_MAX_DATA_LEN, dataLen);
  strncpy(buffer, (const char *)data, msgLen);
  buffer[msgLen] = 0; // Ensure the string is null-terminated

  int value = atoi(buffer); // Convert received data to integer

  if (value == 255) {
    Serial.println("Received 255. Writing to ERM.");
    analogWrite(ERM_PIN, value);  // Write 255 to the ERM motor
  } else {
    analogWrite(ERM_PIN, 0);  // If not 255, turn off the ERM
  }
}

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

  pinMode(ERM_PIN, OUTPUT);  // Set the ERM pin as an output
  analogWrite(ERM_PIN, 0);   // Initially, turn off the ERM

  WiFi.mode(WIFI_STA);
  Serial.println("ESP-NOW Receiver Setup");

  WiFi.disconnect();

  if (esp_now_init() == ESP_OK) {
    Serial.println("ESP-NOW Init Success");
    esp_now_register_recv_cb(receiveCallback);  // Register the receive callback
  } else {
    Serial.println("ESP-NOW Init Failed");
    delay(3000);
    ESP.restart();
  }
}

void loop() {
  // Nothing to do here, just waiting for data
}

Credits

Ideazero Designs

Ideazero Designs

1 project • 2 followers
Electronics | Maker | Hardware | DIY | Open-source 🚀

Comments