Skip to content

20. Project development

Gantt Chart

for downloading/viewing the file Click here

Bill og Meterials

SI.NO DEVICE VALUE QTY
1 MOSFET NSOT23 10
2 SOLENOID VALVE NORMALY CLOSED 2 WAY VALVE 8
3 VR_REGULATOR LM1117SOT223 1
4 CONN_06_FTDI-SMD-HEADER_2SIDE CONN_06_FTDI-SMD-HEADER 1
5 CONN_00X03-SMD-HEADER_2SIDE CONN_03-SMD-HEADER_2SIDE 1
6 CONN_02X02-PINHEAD-SMD CONN_02X2-PINHEAD-SMD 1
7 DIODE CDBM1100-G 8
8 LED RED 1
9 LED GREEN 9
10 CAPASITOR 1UF 2
11 CAPASITOR 100NF 2
12 POWER TERMINAL 0X2 TERMINAL 9
13 RESISTOR 0K 3
14 RESISTOR 1K 8
15 RESISTOR 10K 12
16 RESISTOR 5K 2
17 RESISTOR 500K 8
18 ESP32-S2-WROOM-I (32MB) 1
19 NEOPIXEL LED 8
20 OLED DISPLAY. 1
21 SILICONE TUBE. 6m
22 '4 WAY' JOINT 6
23 'I' JOINT 10
24 'T' JOINT 1
25 AQUARIUM AIR PUMP. 1

Electronics Design

I was planning to make a bord which have a ability to controll 8 solinoid valves and have wifi connecting capablities so i thought of using ESP-32 as the microcontroller as it have inbuild wifi and more than enough pins for connecting solinoid, OLED, and neo pixel and RTOS capablity so I took fusion and strted creating the schematic Screenshot 2022-07-01 085526.jpg and went to PCB Documents and arranged the components and ruted out the PCB wich was ready to be milled out. Screenshot 2022-07-01 085526.jpg the files were exported as monochrome images and milled out.

Screenshot 2022-07-01 085526.jpg

for downloading file Click here


this wouldn’t have been possible if it wasn’t for Shaheen because he is simply mess in electronics.

3D modeling

initally started designing the container by measuring size of a small aquerium i bought some months back during lockdown and reverse engineerring and redesigning it on fusion.

Screenshot 2022-07-01 085526.jpg

and thought of creating seperation chamber and how to hide the tubeings providing the air inside the chamber.

Screenshot 2022-07-01 085526.jpg Screenshot 2022-07-01 085526.jpg

Lasercutting parts

The bubble seperating structure is converted into dxf file and cutted in laser cutter. Screenshot 2022-07-01 085526.jpg for downloading file Click here

After cutting and assembling

Screenshot 2022-07-01 085526.jpg

programming

Being a mechanical engineer, I had little experience with programming, but Senior Abeleetans’s logic and Instructor Jogin’s magic touch in my programme made the project work.



// Header definition
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <SPI.h>
#include "time.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_NeoPixel.h>

#define LED_COUNT 2
#define LED_PIN    27

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

//---------------------------------Delays -----------------------------------------------

#define BUBBLE_BREAK_DELAY 6 //Time in mills to open the solinoid 
#define LINE_DEALY 60 //Time in mills to wait for next line  
#define NUMBER_DEALY 800 //Time in mills to wait for next Number 

//---------------------------------Display Settings--------------------------------------

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

//---------------------------------------------------------------------------------------
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

//---------------------------------------------------------------------------------------
String txtMsg = "";                         // a string for incoming text
int lastStringLength = 0;     // previous length of the String

char alphabet[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
int wantedpos;

// Number metrix defenition

int number[11][8] = {{ // 0
    0b00111000,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b00111000

  }, {         // 1
    0b00001000,
    0b00011000,
    0b00101000,
    0b00001000,
    0b00001000,
    0b00001000,
    0b00001000,
    0b00111110

  }, {         // 2
    0b00111000,
    0b01000100,
    0b00000100,
    0b00001000,
    0b00010000,
    0b00100000,
    0b01111100

  }, {         // 3
    0b00111000,
    0b01000100,
    0b00000100,
    0b00011000,
    0b00000100,
    0b01000100,
    0b00111000
  }, {         // 4
    0b00001000,
    0b00011000,
    0b00101000,
    0b01001000,
    0b11111100,
    0b00001000,
    0b00001000
  }, {         // 5
    0b01111100,
    0b01000000,
    0b01000000,
    0b01111000,
    0b00000100,
    0b00000100,
    0b01111000
  }, {         // 6
    0b00111000,
    0b01000100,
    0b01000000,
    0b01111000,
    0b01000100,
    0b01000100,
    0b00111000
  }, {         // 7
    0b01111111,
    0b00000001,
    0b00000001,
    0b00000010,
    0b00000100,
    0b00001000,
    0b00010000,
    0b00100000
  }, {         // 8
    0b00111000,
    0b01000100,
    0b01000100,
    0b00111000,
    0b01000100,
    0b01000100,
    0b00111000
  }, {         // 9
    0b00111000,
    0b01000100,
    0b01000100,
    0b00111100,
    0b00000100,
    0b01000100,
    0b00111000
  }, {         // :(10)
    0b00000000,
    0b00000000,
    0b00011000,
    0b00000000,
    0b00000000,
    0b00011000,
    0b00000000,
    0b00000000
  }


};


// Char metrix defenition

int text[26][8] = {{ // a
    0b00111000,
    0b01000100,
    0b01000100,
    0b01111100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100


  }, {         // b
    0b01111000,
    0b01000100,
    0b01000100,
    0b01111100,
    0b01001000,
    0b01000100,
    0b01000100,
    0b01111000


  }, {         // c
    0b00111000,
    0b01000100,
    0b01000000,
    0b01000000,
    0b01000000,
    0b01000000,
    0b01000100,
    0b00111000,


  }, {         // d
    0b01111000,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01111000

  }, {         // e
    0b01111100,
    0b01000000,
    0b01000000,
    0b01111000,
    0b01000000,
    0b01000000,
    0b01000000,
    0b01111100

  }, {         // f
    0b01111100,
    0b01000000,
    0b01000000,
    0b01111000,
    0b01000000,
    0b01000000,
    0b01000000,
    0b01000000

  }, {         // g
    0b01111000,
    0b01000100,
    0b01000000,
    0b01000000,
    0b01011100,
    0b01000100,
    0b01000100,
    0b01111000

  }, {         // h
    0b01000100,
    0b01000100,
    0b01000100,
    0b01111100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100

  }, {         // i
    0b01111100,
    0b00010000,
    0b00010000,
    0b00010000,
    0b00010000,
    0b00010000,
    0b00010000,
    0b01111100

  }, {         // j
    0b00111100,
    0b00000100,
    0b00000100,
    0b00000100,
    0b00000100,
    0b00000100,
    0b01000100,
    0b00111000

  }, {         // k
    0b01000100,
    0b01000100,
    0b01001000,
    0b01110000,
    0b01001000,
    0b01000100,
    0b01000100,
    0b01000100

  }
  , {         // l
    0b01000000,
    0b01000000,
    0b01000000,
    0b01000000,
    0b01000000,
    0b01000000,
    0b01000000,
    0b01111100


  }
  , {         // m
    0b01000100,
    0b01101100,
    0b01010100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100

  }, {         // n
    0b01000010,
    0b01000010,
    0b01100010,
    0b01010010,
    0b01001010,
    0b01000110,
    0b01000010,
    0b01000010
  }, {         // o
    0b00111000,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b00111000
  }, {         // p
    0b01111000,
    0b01000100,
    0b01000100,
    0b01111000,
    0b01000000,
    0b01000000,
    0b01000000,
    0b01000000

  }, {         // q
    0b00111000,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01010100,
    0b01001100,
    0b00111100

  }, {         // r
    0b01111000,
    0b01000100,
    0b01000100,
    0b01111000,
    0b01010000,
    0b01001000,
    0b01000100,
    0b00000100

  }, {         // s
    0b01111100,
    0b01000000,
    0b01000000,
    0b01111000,
    0b00000100,
    0b00000100,
    0b01111000
  }, {         // t
    0b01111100,
    0b00010000,
    0b00010000,
    0b00010000,
    0b00010000,
    0b00010000,
    0b00010000,
    0b00010000

  }, {         // u
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b00111000

  }, {         // v
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b00101000,
    0b00010000

  }, {         // w
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01000100,
    0b01010100,
    0b01101100,
    0b01000100
  }, {         // x
    0b01000100,
    0b01000100,
    0b00101000,
    0b00010000,
    0b00101000,
    0b01000100,
    0b01000100,
    0b00000000


  }, {         // y
    0b01000100,
    0b01000100,
    0b00101000,
    0b00010000,
    0b00010000,
    0b00010000,
    0b00010000,
    0b00010000

  }, {         // z
    0b01111100,
    0b00000100,
    0b00001000,
    0b00010000,
    0b00100000,
    0b01000000,
    0b01111100,
    0b00000000

  }


};













//---------------------------------------------------------------------------------------
// Solinoid pin defenition


int pinMap[8] = {18, 19,  5, 17, 14, 4, 12, 16};


//--------------------------------- Time -----------------------------------------------

volatile int h = 0;
volatile int m = 0;
volatile int s = 0;
volatile int hr2 = h % 10; // seperating 1st digit of hour
volatile int hr1 = (h - hr2) / 10; //seperating 2nd digit of hour
volatile int mit2 = m % 10; //seperating 1st digit of muinits
volatile int mit1 = (m - mit2) / 10; //seperating 1st digit of munits


//---------------------------------------------------------------------------------------
// WiFi Settings

const char* ssid     = "Your Wifi Name";                          //WiFi Name
const char* password = "Your Wifi Password";                   // WiFi Password

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "1.asia.pool.ntp.org", 19800);

//--------------- Task Handle -------------------------------

TaskHandle_t Print_Time;
TaskHandle_t Get_Time;
TaskHandle_t NeoPixel;

//--------------- Function Initilizations -------------------------------

void initDisplay();
void initSolinoid();
void initWifi();

void neoPixel(void * parameter);
void printTime(void * parameter);


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

  strip.begin();
  strip.show();
  strip.setBrightness(50);

  //display setup
  initDisplay();

  //Setting solinoid pins
  initSolinoid();

  //connect to WiFi
  initWifi();

  // Create Tasks --------------------------------------
  xTaskCreatePinnedToCore(
    printTime,          /* Task function. */
    "Print_Time",        /* String with name of task. */
    10000,                  /* Stack size in bytes. */
    NULL,                   /* Parameter passed as input of the task */
    3,                      /* Priority of the task. */
    &Print_Time,         /* Task handle. */
    1);                     /* Core where the task should run */
  xTaskCreatePinnedToCore(
    getTime,          /* Task function. */
    "Get_Time",        /* String with name of task. */
    10000,                  /* Stack size in bytes. */
    NULL,                   /* Parameter passed as input of the task */
    3,                      /* Priority of the task. */
    &Get_Time,         /* Task handle. */
    1);                     /* Core where the task should run */
  xTaskCreatePinnedToCore(
    neoPixel,         /* Task function. */
    "NeoPixel",       /* String with name of task. */
    10000,                  /* Stack size in bytes. */
    NULL,                   /* Parameter passed as input of the task */
    3,                      /* Priority of the task. */
    &NeoPixel,        /* Task handle. */
    0);                   /* Core where the task should run */
}

void loop() {
  vTaskDelay(10);
}

//---------------------------------------------------------------------------------------

// Task 1 -> neoPixel --------------------

void neoPixel(void * parameter) {
  Serial.print("neoPixel running on core ");
  Serial.println(xPortGetCoreID());
  for (;;) {

    rainbow(10);

  }
  vTaskDelete( NULL );
}

// Task 2 -> get Time --------------------

void getTime(void * parameter) {
  Serial.print("getTime running on core ");
  Serial.println(xPortGetCoreID());
  for (;;) {
    timeClient.update(); //gets the current time from the NTP server.
    h = timeClient.getHours(); //gets hour seperatly from the NTP server.
    m = timeClient.getMinutes(); //gets minuits seperatly from the NTP server.
    s = timeClient.getSeconds(); //gets seconds seperatly from the NTP server.
    hr2 = h % 10; // seperating 1st digit of hour
    hr1 = (h - hr2) / 10; //seperating 2nd digit of hour
    mit2 = m % 10; //seperating 1st digit of muinits
    mit1 = (m - mit2) / 10; //seperating 1st digit of munits
    vTaskResume(Print_Time);
    vTaskDelay(1000);
  }
  vTaskDelete( NULL );
}

// Task 3 -> printTime --------------------

void printTime(void * parameter) {
  Serial.print("printTime running on core ");
  Serial.println(xPortGetCoreID());
  vTaskSuspend(NULL);
  for (;;) {

    display.clearDisplay();
    display.display();

    display.setTextSize(3);
    display.setCursor(21, 30);
    display.print(hr1);
    display.print(hr2);
    display.print(":");
    display.print(mit1);
    display.print(mit2);
    display.display();

    //---------------------------------------------------------------------------------------
    // calling function activate the solinoids
    /*
        printNum(hr1);
        vTaskDelay(NUMBER_DEALY);
        printNum(hr2);
        vTaskDelay(NUMBER_DEALY);
        printNum(10);
        vTaskDelay(NUMBER_DEALY);
        printNum(mit1);
        vTaskDelay(NUMBER_DEALY);
        printNum(mit2);
        vTaskDelay(NUMBER_DEALY);
      }
      vTaskDelete( NULL );*/

    if (Serial.available() > 0)
    {
      txtMsg = Serial.readString();
      //Serial.println(txtMsg);
      int k = txtMsg.length();
      for (int i = 0; i < k; i++)
      {
        char l = txtMsg.charAt(i);

  for (int j = 0; j <= 25; j++) {
    if (l == alphabet[j]) {
      wantedpos = j;
      Serial.print("-");
      Serial.print(wantedpos);
      printtext(wantedpos);
      vTaskDelay(NUMBER_DEALY);
      break;
    }
      }
    }

    Serial.flush();
  }
  else
  {
    printNum(hr1);
        vTaskDelay(NUMBER_DEALY);
        printNum(hr2);
        vTaskDelay(NUMBER_DEALY);
        printNum(10);
        vTaskDelay(NUMBER_DEALY);
        printNum(mit1);
        vTaskDelay(NUMBER_DEALY);
        printNum(mit2);
        vTaskDelay(NUMBER_DEALY);

    }
  }
  vTaskDelete( NULL );
}

void printNum(int num) { // activating the solinoids
  for (int j = 0; j < 8; j++) {
    for (int i = 0; i < 8; i++) {
      bool out = ((number[num][j] << i) & 0b10000000) & 0b10000000;
      digitalWrite(pinMap[i], out);
    }
    vTaskDelay(BUBBLE_BREAK_DELAY);
    for (int i = 0; i < 8; i++) {
      digitalWrite(pinMap[i], 0);
    }
    vTaskDelay(LINE_DEALY);
  }
}

void printtext(int tex) { // activating the solinoids
  for (int j = 0; j < 8; j++) {
    for (int i = 0; i < 8; i++) {
      bool out = ((text[tex][j] << i) & 0b10000000) & 0b10000000;
      digitalWrite(pinMap[i], out);
    }
    vTaskDelay(BUBBLE_BREAK_DELAY);
    for (int i = 0; i < 8; i++) {
      digitalWrite(pinMap[i], 0);
    }
    vTaskDelay(LINE_DEALY);
  }
}














void initDisplay() {
  //display setup
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  vTaskDelay(2000);
  display.clearDisplay();

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

void initSolinoid() {
  for (int i = 0; i < 8; i++) {
    pinMode(pinMap[i], OUTPUT);
  }

}

void initWifi() {
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(NUMBER_DEALY);
    Serial.print(".");


  }
  Serial.println(" CONNECTED");
}



void rainbow(int wait) {
  for (long firstPixelHue = 0; firstPixelHue < 5 * 65536; firstPixelHue += 256) {
    for (int i = 0; i < strip.numPixels(); i++) {
      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show();
    vTaskDelay(wait);
  }
}

Testing

the program and the divice was tested and itrated mulitiple times to get the final output.

solinoid valve testing

at first i needed to check wether all the valves are working properly and the pump used have the capasity to make bubbles

now i had to check how it will look like in lighted condition.

NTP and digit testing

it was the 1st itration of showing numbers.

Final time test with calibrated digits with RTOS

Packaging

after all the testing i needed to make a casing for holding the solinoid PCB and valves so i went ro fusion and started designing a box container for holding the pcb and and solinoidal valves wich could be cut in acleric sheet Screenshot 2022-07-01 085526.jpg for downloading file Click here
.the parts were cut out of acleric in laser cutter Screenshot 2022-07-01 085526.jpg
for making the box look better i was planing to give it a mat black vinayle wrap so i send the same file linked above to vinyle cutter via mods and wraped it over the earlier cutted aclerics. Screenshot 2022-07-01 085526.jpg and 3d printed a oled holder and tube organizeres Mufeed Sir’s assistance here was invaluable.
Screenshot 2022-07-01 085526.jpg

Completed 3D Model

completed the whole 3D model of how the divice will look. Screenshot 2022-07-01 085526.jpg

Rendered output.

as am new to fusion and most of the other weeks i used inventor 3D it was bit difficut to Render a proper output so my friend Ajith/തല helped me to do this who is pro in fusion rendering. Screenshot 2022-07-01 085526.jpg for downloading file Click here

Real Outcome

Screenshot 2022-07-01 085526.jpg

Final Outcome video

PROJECT VIDEO

Click here access the presentation video.

PROJECT SLIDE

Click here access the presentation slide. groupmillig.jpg

groupmillig.jpg
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.