Final Project

Project Selection



Project Criteria

  1. Must have at least 1 output and 1 input.
  2. Include a hardware component and a mechanical part.
  3. Preferably involves something moving controlled by electronics in response to specific events.
  4. Utilize a maximum number of Fab Lab tools and machines during production.
  5. Project files must be open source and accessible for the community.


Project Sketch

Considering the Fab Lab criteria for the final project, here is is my idea and the sketch.

The AquaSense Smart Swim Coach elevates your swim with real-time feedback, lap count, and time tracking. It alerts for pace and breathing, offers personalized coaching, and sets goals. With a waterproof design, it's your all-in-one companion for a smarter and more effective swimming experience.

Project Management

Here are few more ideas for my final project.



Project 1

A fan-powered wall climbing robot employs airflow for adhesion, combining suction and thrust to climb vertical surfaces. Ideal for inspection and maintenance, this innovative design ensures stability and controlled movement, making it a versatile solution for navigating and accessing hard-to-reach areas on walls and structures.

Project 2

A soft robotics-based massaging robot for feet leverages gentle, customizable pressure on specific points to provide a targeted and relaxing massage experience. Mimicking the principles of reflexology, this innovative robot adapts soft robotic technology to enhance comfort, relieve tension, and promote well-being through precise pressure point stimulation.



Project 3

An LED cube matrix as an art installation is a visually captivating and dynamic creation. Comprising a three-dimensional array of programmable LED lights, the cube matrix illuminates and morphs into intricate patterns, colors, and animations. This interactive and versatile piece of art engages viewers, transforming spaces with its luminous, ever-changing displays.



Project 4

Develop a tactile musical instrument for the deaf, translating sound into vibrations and visual cues. Utilize sensors to detect musical nuances, converting them into vibrations or light patterns. Ensure a versatile and inclusive interface, allowing deaf individuals to experience and create music through touch and visual feedback.



CAD

Final Project Design


After trying out all tools, I've designed the watch using Fusion 360.


  1. First, I wanted a display for my watch to design an accurate case. I thought of using Waveshare 1.69inch LCD Display Module. I downloaded the cad file of it from grabcad.com, So here's the Waveshare 1.69 inch LCD Display Module.
  2. Project Management
  3. I've designed a case for the display module, also leaving considerable space for the electronic components of the watch. I've assigned the material as stainless steel.
  4. Project Management
  5. Next, I constructed the overall the body of the watch i.e. an enclosure to the case and the strap.
  6. Project Management
  7. This pin-like object will help to adjust the strap of the watch.
  8. Project Management
  9. These are the holes of the strap that are correctly fittable to the pin.
  10. Project Management
  11. Next, I fit the case inside the watch body.
  12. Project Management
  13. Now, I've added material glass to the case and I've chosen acrylic ember to distinguish it easily.
  14. Project Management
  15. Next, I hid the glass and added the display I designed using Figma using decal.
  16. Project Management
  17. This is the final look of the design.
  18. Project Management

Final Project Render


I've used Fusion 360 for the rendering. So I opened Render Studio and played around with the environment settings to get these renders.


  1. Render look 1
  2. Project Management
  3. Render look 2.
  4. Project Management
  5. Render look 3. Here, the material was changed to rubber.
  6. Project Management

Final Project Animation


I used Fusion 360 to animate my design.


    I watched a tutorial on animations and tried to implement it on my design. So here, I selected a frame and used transform to components to choose each component and moved. I've also used view to make assembly of the components shown from different directions. So here's the animated video:



Output Devices

Watch Display


The 1.28" Round LCD Display Module features an embedded GC9A01 driver and utilizes the SPI bus for communication. It is a 240x240 Round RGB LCD Display featuring a four-wire SPI communication interface. By utilizing SPI, it efficiently utilizes GPIO ports and enables faster communication speeds. Similar in size to the 240x240 square LCD, it distinguishes itself with rounded edges. This LCD employs the GC9A01 driver, offering a resolution of 240RGB×240 dots.

Coming soon
Pin Description
VCC Power (3.3V / 5V input)
GND Ground
DIN SPI data input
CLK SPI clock input
CS Chip selection, low active
DC Data/Command selection (high for data, low for command)
RST Reset, low active
BL Backlight

Coming soon

Interfacing with ESP 32

After refering the documentation of the display module, I thought of testing it out with ESP 32 Module.


So I referred this documentation and documentation for the testing.


Here's the pin connections


ESP 32 Pin Display Pin
3V3 VCC
GND GND
G23 DIN
G18 CLK
G22 CS
G16 DC
G4 RST
3V3 BL

Now I need to set up the library. I searched for “TFT_eSPI” and installed it. I need to make a couple of modifications in order to get the library working, as it was meant for several types of displays and processors. Here is what I did:
Using your File explorer, I navigated to Arduino Libraries folder, which is inside my Arduino folder in Documents. Look for the TFT_eSPI folder and Inside the folder, I found several files so I looked for the User_Setup.h file. I opened the file using visual code studio and made the following edits:
Comment out the line defining the ILI9341 driver. Uncomment the line defining the GC9A01 driver. Comment out all the SPI definitions for the ILI9341.
For ESP 32, set MOSI to 23. set SCLK to 18. set CS to 22. set DC to 16. set RST to 4. Then I saved the file.

Coming soon

A great demo code sample is the Animated_dial sketch, which is found inside the Sprites menu item from File>Examples>TFT_eSPI. This demonstration code will produce a “dial” indicator on the display, along with some simulated “data” (really just a random number generator). In order to run this sketch, I need to install another library. After installation, the code is uploaded and I get this output.



Next example is called Boing Ball Demo and it can be found in Example>TFT_eSPI> DMA Test>Boing Ball Demo


Next Sketch is this Scrolling Sprite Message which can be found in Example> TFT_eSPI> Sprite> ScrollingSprite 16 Bit. I made a few edits to the code to get this.


Seeed XIAO nRF52840 Sense

Since my final project is a swimming watch make a board with esp 32 module will make the watch size really big. So I found out a suitable board for my final project to interface with the display.

Coming soon

So I referred this documentation to understand the board and followed the steps of board installation. I implemented blink program and additionally, I tried to test the inbuilt sensor which is an accelerometer.


So I referred this documentation and used the code there to test the sensor. That documentation is about using tinyml to sense the human acitivity by one of the instructors Salman Farris.



  // XIAO BLE Sense LSM6DS3 Data  Forwarder 

  #include "LSM6DS3.h"
  #include "Wire.h"

  //Create a instance of class LSM6DS3
  LSM6DS3 myIMU(I2C_MODE, 0x6A);  //I2C device address 0x6A

  #define CONVERT_G_TO_MS2 9.80665f
  #define FREQUENCY_HZ 50
  #define INTERVAL_MS (1000 / (FREQUENCY_HZ + 1))

  static unsigned long last_interval_ms = 0;


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

    if (myIMU.begin() != 0) {
      Serial.println("Device error");
    } else {
      Serial.println("Device OK!");
    }
  }



  void loop() {
    if (millis() > last_interval_ms + INTERVAL_MS) {
      last_interval_ms = millis();
      Serial.print(myIMU.readFloatAccelX() * CONVERT_G_TO_MS2, 4);
      Serial.print('\t');
      Serial.print(myIMU.readFloatAccelY() * CONVERT_G_TO_MS2, 4);
      Serial.print('\t');
      Serial.println(myIMU.readFloatAccelZ() * CONVERT_G_TO_MS2, 4);
    }
  }


So I tried to keep the microcontroller with my watch and tried to immitate the swimming movements with my hands. The values are getting displayed accordingly.



So for my final project, I'm thinking of using tinyml to train the movements of somersault to count the number of laps. I am a little bit familiarised with tinyml since I had attended a workshop about it by one of the instructor Salman Farris before Fab Academy. So the workshop was about using tinyml to sense the movements of the microcontroller. A similar implementation is available in this documentation about using tinyml for sensing human activity.


So here is the library generated during the workshop> Magic Wand


Next, I uploaded this code to the board


  
  /* Includes ---------------------------------------------------------------- */
  #include < Xiao-nRF-MagicWand-LightControl_inferencing.h > //replace the library name with yours
  #include "LSM6DS3.h"

  /* Constant defines -------------------------------------------------------- */
  #define CONVERT_G_TO_MS2    9.80665f
  #define MAX_ACCEPTED_RANGE  2.0f        // starting 03/2022, models are generated setting range to +-2, but this example use Arudino library which set range to +-4g. If you are using an older model, ignore this value and use 4.0f instead
  #define INTERVAL_MS (1000 / (FREQUENCY_HZ + 1))
  static unsigned long last_interval_ms = 0;

  LSM6DS3 myIMU(I2C_MODE, 0x6A);  //I2C device address 0x6A

  static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal

  /**
  * @brief      Arduino setup function
  */
  void setup()
  {
      // put your setup code here, to run once:
      Serial.begin(115200);
      // comment out the below line to cancel the wait for USB connection (needed for native USB)
      while (!Serial);
      Serial.println("Edge Impulse Inferencing Demo");

      if (!myIMU.begin()) {
          ei_printf("Failed to initialize IMU!\r\n");
      }
      else {
          ei_printf("IMU initialized\r\n");
      }

      if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != 3) {
          ei_printf("ERR: EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME should be equal to 3 (the 3 sensor axes)\n");
          return;
      }
  }

  /**
  * @brief Return the sign of the number
  * 
  * @param number 
  * @return int 1 if positive (or 0) -1 if negative
  */
  float ei_get_sign(float number) {
      return (number >= 0.0) ? 1.0 : -1.0;
  }

  /**
  * @brief      Get data and run inferencing
  *
  * @param[in]  debug  Get debug info if true
  */
  void loop()
  {
      //ei_printf("\nStarting inferencing in 2 seconds...\n");

      delay(2000);

      //ei_printf("Sampling...\n");

      // Allocate a buffer here for the values we'll read from the IMU
      float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 };

      for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += 3) {
          // Determine the next tick (and then sleep later)
          uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000);

          //IMU.readAcceleration(buffer[ix], buffer[ix + 1], buffer[ix + 2]);

          buffer[ix+0] = myIMU.readFloatAccelX();
          buffer[ix+1] = myIMU.readFloatAccelY();
          buffer[ix+2] = myIMU.readFloatAccelZ();



          for (int i = 0; i < 3; i++) {
              if (fabs(buffer[ix + i]) > MAX_ACCEPTED_RANGE) {
                  buffer[ix + i] = ei_get_sign(buffer[ix + i]) * MAX_ACCEPTED_RANGE;
              }
          }

          buffer[ix + 0] *= CONVERT_G_TO_MS2;
          buffer[ix + 1] *= CONVERT_G_TO_MS2;
          buffer[ix + 2] *= CONVERT_G_TO_MS2;

          delayMicroseconds(next_tick - micros());
      }

      // Turn the raw buffer in a signal which we can the classify
      signal_t signal;
      int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal);
      if (err != 0) {
          ei_printf("Failed to create signal from buffer (%d)\n", err);
          return;
      }

      // Run the classifier
      ei_impulse_result_t result = { 0 };

      err = run_classifier(&signal, &result, debug_nn);
      if (err != EI_IMPULSE_OK) {
          ei_printf("ERR: Failed to run classifier (%d)\n", err);
          return;
      }

      // print the predictions
    // ei_printf("Predictions ");
    // ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
    // result.timing.dsp, result.timing.classification, result.timing.anomaly);
      //ei_printf("\n");
      for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
    // ei_printf("    %s: %.5f\n", result.classification[ix].label, result.classification[ix].value);
      if (result.classification[ix].value > .5) {
          ei_printf("%s \n", result.classification[ix]);
      }
      }

      //  if (result.classification[ix].value > .5) {
      //     ei_printf("    %s: %.5f\n", result.classification[ix].label, result.classification[ix].value);
      // }
      // }


  #if EI_CLASSIFIER_HAS_ANOMALY == 1
      ei_printf("anomaly score: %.3f\n", result.anomaly);
  #endif
  }

  #if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_ACCELEROMETER
  #error "Invalid model for current sensor"
  #endif



So this code will sense the motion of the microcontroller and identify if it is circle, idle or swish.



System Integration

System Diagram

Project Management

Production Processes


3D Printing the Watch Case

Once the design is finalized, the watch case is 3D printed using TPU (Thermoplastic Polyurethane) material. 3D printing allows for precise manufacturing of complex shapes and ensures that each watch case is uniform in quality.

Milling the Mold

The next step involves milling the mold for casting the watch case using wax. A CNC (Computer Numerical Control) milling machine is used to carve out the mold based on the 3D design. This process ensures accuracy and consistency in the production of molds.

Casting the Watch Case

Silicone rubber is used to cast the watch case from the wax mold. Silicone is chosen for its flexibility, durability, and ability to replicate intricate details. The silicone is poured into the mold and allowed to cure, forming the final watch case.


Tasks & Schedule

Project Management

BOM


SL No Material Amount
1 Seeed XIAO nRF52840 Sense ₹1,899.00
2 Seeed Studio 1.28-inch Round Touch Display for XIAO ₹1,899.00
3 400 mAh 3.7V single cell Rechargeable LiPo Battery ₹189.00
4 TP4056 1A Li-ion lithium Battery Charging Module With Current Protection – Type C ₹11.00
5 NeoPixel WS2812 RGB Addressable LED ₹359.00
6 3*6*2.5 mm SMD Tactile Switch ₹80.00
7 3V 6*14MM Vibration Hollow Cup Motor ₹49.00
8 Smart Watch Belt Steel Button ₹20.00
9 SeSun eTPU-95A 3D Printing Filament-Transparent Purple ₹2,149.00
10 Aditya Silicone Rubber RTV – 3915 – 1 Kg. – German Materials Silicone ₹1,395.00
Total ₹8,050.00

Operation & Features


Mode of Operation


Setting Targets

Users can set their target time and speed for their swimming sessions through a dedicated smartphone app. The app provides a user-friendly interface to input and adjust these targets easily.

Real-Time Data Updates

The Aqua Sense smartwatch is integrated with the smartphone app to provide real-time updates on various swimming metrics. The app displays data such as speed, time, and the number of laps completed.

Monitoring and Alerts


Speed and Time Monitoring

The watch continuously monitors the swimmer's speed and elapsed time. It uses sensors and the Seeed XIAO nRF52840 Sense to track these parameters accurately.

Lap Counting

The watch also counts the number of laps completed, providing swimmers with precise tracking of their workout.

Feedback Mechanisms


Vibration Alerts

If the swimmer's speed falls below the set target or if they are not meeting the target time, the watch sends vibration alerts. These alerts help swimmers adjust their pace without needing to look at the watch.

Neopixel LED Indications

The watch uses NeoPixel WS2812 RGB addressable LEDs to provide visual feedback. The LEDs change color based on the swimmer's performance:
Less Speed: A specific color (e.g., red) indicates that the swimmer's speed is below the target.
High Speed: Another color (e.g., green) indicates that the swimmer's speed is above the target.
Meeting Targets: A neutral color (e.g., blue) indicates that the swimmer is on target.