Skip to content

Vision Voice Development

Week01

Visualize

To clearly visualize my final project, I have used canva to jot down the ideas and features of my project.

image

Here is the link to my canva for reference

Circuit

Using Canva I have also made a Draft of the circuit.( The circuit is not finilized and I need to rework on it. ^o^)

image

Here is the link to detailed connection.

Week02 - Cardboard Prototyping.

Today, our local instructor guided us through the process of cardboard prototyping, which was both fun and interesting. Afterward, we were given two hours to complete our first prototype for our final projects.

Hero Shot

image

I started by making the glove and attaching the flex sensors.

image

Next, I researched every component to find their specific dimensions, such as thickness and height. I carefully drew these dimensions onto the cardboard and cut them out using blades and scissors.

image

After that I estimated the size of the casing and drew on the cardboard.

image

Once the pieces were ready, I assembled everything to create the final structure.

image

Key Takeaways( Things I need to work on here after.)

Cloth Glove Fabrication: Figuring out how to transition the design from cardboard to actual fabric.

Sensor Integration: Determining the best method to securely attach the flex sensors to the cloth glove.

Casing Design & Wire Management: Planning the internal layout of the casing to fit the PCB and organize wires neatly.

Accessibility Mechanism: Designing a lid system (likely using screws) that allows you to easily open the casing for maintenance.

Material Constraints: Accounting for the specific thickness of your final materials and hardware (like screw sizes) in your design

Future Plans

Here after I plan to make a working prototype with the cardboard and test my programs and connections.

*Thank You

Week04

Simulations and Prototyping

I wanted to make something for my final project. I wanted to use the XIAO ESP32C3 board and display text when a certain value is reached from the flex sensor. This will help me understand the flex sensor values better, which is a really important component for my final project.

I gathered all the components and made the circuit. The main purpose of this was to test the components and be fimilar with the circuit. In the comming weeks I plan to test all the compoents.

image

image

After that I downloaded the following libraries for the OLED display:

Adafruit_GFX.h Adafruit_SSD1306.h

image

I then added the XIAO ESP32C3 board to the Arduino IDE. This is the link: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json

I added the link to the preference URL tab. Then I downloaded the ESP32 from the Board Manager.

image

image

After carefully installing all the libraries and components, I uploaded the code to the XIAO ESP32C3 board.

image

image

Code

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

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

#define FLEX_PIN D0

// Your exact ranges
#define IDLE_MIN    350   // 350-360 = Bend sensor (idle)
#define HELLO_MIN   280   // 280-345 = Hello World
#define VISION_MIN  200   // 200-275 = I Am Vision Voice
#define THANKS_MIN  110   // 110-195 = Thank You

const char* words[] = {
  "HELLO WORLD",
  "I AM VISION VOICE",
  "THANK YOU"
};

int lastState = -1;

void displayWord(const char* word) {
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextWrap(true);

  int textSize = (strlen(word) > 9) ? 1 : 2;
  display.setTextSize(textSize);

  int16_t x1, y1;
  uint16_t w, h;
  display.getTextBounds(word, 0, 0, &x1, &y1, &w, &h);
  int yPos = (SCREEN_HEIGHT - h) / 2;
  int xPos = (SCREEN_WIDTH - w) / 2;
  if (xPos < 0) xPos = 0;

  display.setCursor(xPos, yPos);
  display.println(word);
  display.display();
}

void displayIdle() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(20, 28);
  display.println("Bend the sensor...");
  display.display();
}

void setup() {
  Serial.begin(115200);
  pinMode(FLEX_PIN, INPUT);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 allocation failed");
    while (true);
  }

  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 20);
  display.println("VISION");
  display.setCursor(30, 42);
  display.println("VOICE");
  display.display();
  delay(2000);

  displayIdle();
}

void loop() {
  int flexValue = analogRead(FLEX_PIN);

  Serial.print("Flex Value: ");
  Serial.println(flexValue);

  int currentState = -1;

  if (flexValue >= IDLE_MIN) {
    currentState = -1;
  } else if (flexValue >= HELLO_MIN) {
    currentState = 0;
  } else if (flexValue >= VISION_MIN) {
    currentState = 1;
  } else if (flexValue >= THANKS_MIN) {
    currentState = 2;
  }

  if (currentState != lastState) {
    if (currentState == -1) {
      displayIdle();
    } else {
      displayWord(words[currentState]);
    }
    lastState = currentState;
  }

  delay(100);
}

Code Explanation

After that I wrote the code. Note that the code wasn't entirely written by me. It was written with the help of Claude AI.

Libraries Used

I used three libraries for this project:

  • Wire.h — this handles the I2C communication between the microcontroller and the OLED display
  • Adafruit_GFX.h — this is a base graphics library that lets you draw text and shapes on a display
  • Adafruit_SSD1306.h — this one is specifically for controlling the SSD1306 OLED display

How the Code Works

1. Defining the Screen and Pin

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define FLEX_PIN D0

This part basically sets up the OLED display size, which is 128×64 pixels, and tells the code which pin the flex sensor is connected to — in this case, D0.

The OLED_RESET -1 just means I'm not using a separate reset pin for the display.


2. Setting the Flex Sensor Ranges

#define IDLE_MIN    350
#define HELLO_MIN   280
#define VISION_MIN  200
#define THANKS_MIN  110

This was honestly the most important and tricky part I had to figure out. The flex sensor gives out different analog values depending on how much it's being bent. So I had to test it a bunch of times using the Serial Monitor and note down what values came out at different bend positions.

Here are the ranges I ended up with:

Flex Value Range What it Shows
350 – 360 Idle (not bent)
280 – 345 "HELLO WORLD"
200 – 275 "I AM VISION VOICE"
110 – 195 "THANK YOU"

I also stored all the phrases in an array so I can just call them by their index number instead of retyping them every time:

const char* words[] = {
  "HELLO WORLD",
  "I AM VISION VOICE",
  "THANK YOU"
};


3. Tracking the State

int lastState = -1;

I used a variable called lastState to keep track of what's currently being shown on the display. This way, the display only updates when the state actually changes — so it's not constantly refreshing for no reason. -1 means the display is in idle mode.


4. The displayWord() Function

void displayWord(const char* word) {
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextWrap(true);

  int textSize = (strlen(word) > 9) ? 1 : 2;
  display.setTextSize(textSize);

  int16_t x1, y1;
  uint16_t w, h;
  display.getTextBounds(word, 0, 0, &x1, &y1, &w, &h);
  int yPos = (SCREEN_HEIGHT - h) / 2;
  int xPos = (SCREEN_WIDTH - w) / 2;
  if (xPos < 0) xPos = 0;

  display.setCursor(xPos, yPos);
  display.println(word);
  display.display();
}

This is the function that actually puts the text on the OLED screen. I added a small bit of logic here to handle text sizing:

  • If the phrase is longer than 9 characters, it uses a smaller text size (1) so everything fits on the screen
  • If it's shorter, it uses size 2, which looks bigger and easier to read

I also made the text centered on the screen using getTextBounds(). What this does is calculate the width and height of the text first, and then figure out the exact x and y position to place it right in the middle:

int yPos = (SCREEN_HEIGHT - h) / 2;
int xPos = (SCREEN_WIDTH - w) / 2;


5. The displayIdle() Function

void displayIdle() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(20, 28);
  display.println("Bend the sensor...");
  display.display();
}

This is a simple function that shows the idle message "Bend the sensor..." whenever the flex sensor is in its resting position (not bent). It just lets the user know that the device is ready and waiting.


6. The Setup Function

void setup() {
  Serial.begin(115200);
  pinMode(FLEX_PIN, INPUT);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 allocation failed");
    while (true);
  }

  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 20);
  display.println("VISION");
  display.setCursor(30, 42);
  display.println("VOICE");
  display.display();
  delay(2000);

  displayIdle();
}

When the board first powers on, here's what happens step by step:

  1. The Serial Monitor starts at a baud rate of 115200 (useful for debugging)
  2. The flex sensor pin is set as an input
  3. The code checks if the OLED display started successfully — if it didn't, it prints an error and just stops
  4. It then shows a startup screen saying "VISION VOICE" for 2 seconds
  5. After that, it switches over to the idle screen

7. The Main Loop

void loop() {
  int flexValue = analogRead(FLEX_PIN);

  Serial.print("Flex Value: ");
  Serial.println(flexValue);

  int currentState = -1;

  if (flexValue >= IDLE_MIN) {
    currentState = -1;
  } else if (flexValue >= HELLO_MIN) {
    currentState = 0;
  } else if (flexValue >= VISION_MIN) {
    currentState = 1;
  } else if (flexValue >= THANKS_MIN) {
    currentState = 2;
  }

  if (currentState != lastState) {
    if (currentState == -1) {
      displayIdle();
    } else {
      displayWord(words[currentState]);
    }
    lastState = currentState;
  }

  delay(100);
}

This is the main loop that keeps running over and over. Here's what it does:

  1. It reads the analog value from the flex sensor every 100 milliseconds
  2. It also prints the value to the Serial Monitor — this was super helpful when I was testing and figuring out the ranges
  3. It then checks which range the value falls into and sets the currentState accordingly
  4. If the currentState is different from the lastState, it updates the display — either showing the idle message or the matching phrase
  5. lastState gets updated so the display doesn't keep refreshing unnecessarily

Important Improvement

I made the display update only when the state changes:

  • Prevents flickering
  • Makes the output much smoother

Results

image


Here when I bend the flex sensor the text changes to the corresponding phrase that I setup in the Code. Yayyy! :D