Week #1

computer-controlled cutting

Vinyl cutter

For my first assignment, I designed and cut a vinyl sticker.
After a failed attempt with an ambitiously small sticker, I've learned my lesson and designed a larger one that came out perfect.
I used Mods to translate the designs to machine instructions.

Laser cutter

For the laser cutting assignment, I wanted to design, cut, and build an old plane model.
As a reference, I used a model I found online at freepatternsarea.com.
Although the reference was helpful, it still took time to design the plane since I was very careful about the small details of the design. After getting used to the parametric design, things started to go much more smoothly, and part by part, I finished the first draft and was ready to try it out!

Failed attempt #1

A few seconds after I started to cut, I noticed that the cutting speed is way too slow. With help from Dave, I understood I didn't export my CAD correctly and the 3D parts were projected with multiple lines on top of each other.

Failed attempt #2

After figuring out how to export correctly, I went on and tried to cut again. This time the cutting speed was too high, creating shallow cuts that did not go al the way through the cardboard.

Success!

After some small tweaks, I cut the parts again and assembled everything. I was so excited that it was successful, and many parts that I was sure will not work on the first try fit perfectly.
The overall result was beyond my expectations - the model felt robust and durable.
My main concern was the top wing as I was afraid that its joins left too much room for movement. After asking Alfonso about that, I was already prepared with a solution but was happy to see that it was durable and steady enough.

Design files

Elephant sticker
Plane DXF file

-------

Week #2

electronics production

Milling the board

For this week we were assigned to mill, solder, and program a mil an in-circuit programmer that includes a microcontroller. After quick training on the mill, I got into milling my board. The process was relatively quick and did not require too much creativity. However, I did fail on my first attempt, after interfering with the calibration process while replacing the tip.
If you'll look closely you will see that the resulting board (on the left) is different than the outlines (right and center). That is because I used a slightly different design that Anthony made.

Soldering

Soldering the components was exciting since it made the board look like an actual functioning chip. I soldered before, and after getting used to the small size of the components the process went pretty well. I soldered two 0 resistors, a 1μ capacitor, two cable connectors, and a microcontroller.

Programming the chip

Unlike the previous parts, this one was not fast and easy. Installations on an M1 MacBook are a tough mission, and even after 2 hours of terminal commands we could'nt make it work. Both EDBG and pyOCD refused to let me program my chip.
Eventually I gave up and used a Windows computer to program it.

-------

Week #3

3D scanning & printing

Scanning

The scanning process was way quicker then I expected. I wanted to scan a small rubber duck and used the Revpoint scanner to do that.
I took a few tries to get it to work, but I was surprised of the results. The model that attached here is a compressed version of the scanning which consisted of much more data, so in practice the scanner can produce much smoother results.

Printing

3d printing always seems like magic to me. You send a 3d file and a few hours later get exactly what you wanted. This week I realized that it's not that simple.
It took me three prints to get my original plan to work - each took several hours. Even my backup plan wasn't successful and took two tries as well.
I assume this slow process of learning from mistakes gets faster with experience, and yet, it can be frustrating to wait 4 hours for a print and only then understand that you need to change your design. The mistakes I had were mostly because I didn't estimate the performance of the machines correctly and I will elaborate on each later. I believe that my next experience with this tool will be much smoother and I feel like Iv'e learned a lot this week.

The Lamp

For my original idea, I wanted to create a lamp that looks boring when off, but when turned on reveals a unique shadow pattern.
It took several iterations to get the design I imagined: a web-like structure inside a seemingly boring cylinder. A sliced version of the design is attached.

The Spinner

When my original idea ran into some problems with my original idea, I thought it can be helpful to design a good backup model.
I wanted to print a fidget spinner in one piece since the idea of printing a functioning ball bearing seemed exciting to me.

-------

Week #4

electronics design

Version 1

This week was less creatively challenging than most of the weeks of the class. I started by modifying the simple SAM-D11C board and added an LED and a button.
That was the first time I used fusion to design a PCB or designed a circuit in general. It took me some time to get used to the workflow but at the end of the week, I noticed that I felt much more comfortable with that. I was happy to learn another complementary skill after electronics production week and I am looking forward to embedded programming week, which will add another skill on top of these two.
After a pretty straightforward design process, I had my first version of the PCB and was ready to mill. I milled the board and soldered the components and that whole process went smoothly without any issues.
However, programming the board was harder due to the EDBG-mac compatibility problems, but with Anthony's help, I was able to get it programmed with the 'echo' code.

Version 2.0

After reviewing my board, I noticed that a lot of optimization can be done to significantly reduce the area of the board and improve the arrangement of the parts.
I started tweaking my routing step by step while making sure I am not violating the design rules. Ultimately, I got a much smaller and better-looking PCB design.
Although I had a programmed board by that point, I wanted to see if the second version is still programmable. I milled and populated the board and went on to program it.
While trying to program it we noticed that when the board and the programmer are connected to different power supplies, the programmer cannot find the board. Anthony suggested that this can happen due to disconnected grounds, and indeed that was the situation.
To solve that, I added a jumper wire between the two disconnected grounds and successfully programmed the board.

-------

Week #5

computer-controlled machining

Design

Traditional woodworking was a hobby of mine way before coming to MIT, and so far, I have built a few furniture pieces that I am really proud of. However, during this past week, I have learned that computer-controlled woodworking requires different skills, and poses different issues to consider.
The idea of building a chair is sitting at the back of my mind for a long time, and I knew it will be a perfect fit for this week's assignment. I wanted to create a light design with curved surfaces and a smooth appearance, that can fit different environments easily while also keeping an impressive presence.
After sketching the legs and the 'ribs' of the chair, I added the supports and quickly had the first version of the design.

Original design

Adjustments

When I started preparing the CAM, I noticed that only cutting the ribs will require seven 48"×48" sheets of OSB, which was much more than I could afford because of both machine time and the amount of material.
I tried to change the design and reduce the amount of material it requires. Making it fit into two OSB sheets while keeping the design characteristics and general appearance was an enjoyable challenge that felt like a puzzle.
Luckily my design was relatively constrained and parametric, so updating it after most of it was complete wasn't extremely hard.
I reduced the number of ribs from 20 to 12, increased the angle of the ribs so it'll be easier to nest them on the sheet, and generally made all the parts smaller. After assembling the chair, I added a support plate at the bottom to make it more robust. After many iterations, I made it fit into two sheets but was concerned that the result will be less stable and too small.

Final design

CAM & Cutting

With Anthony's great help, I was able to get the CAM done pretty quickly and had it ready to cut. We added 'dog bones' to all the ribs joints but left the legs as designed to get a cleaner look at the more exposed joints.
The cutting process was surprisingly fast and took less than 15 minutes. However, removing the pieces from the machine bed was a lot more challenging. Since some of them were pretty thin and fragile on their own, it required us to be extra careful and we still broke one of the ribs.
Anthony was able to extract the second sheet as a whole and saved us the trouble of extracting each piece individually. Later we cut a few more ribs from scrap pieces to replace the broken ones. I think that was the most challenging and stressful part of this job and I felt a huge relief when we were done with it.
I got plenty of help from Anthony throughout the week and especially during this part, and I thank him a lot for that.

Assembly & Finish

The assembly process felt more similar to the woodworking experience I had before. It allowed me to get a better understanding of the material and its behavior and also get some important conclusions about my design.
I started with gluing the legs, then assembled the supports, and finally attached the ribs. As can be seen in the attached sketch, the main problem I found during the assembly was that I designed the ribs in a way that the top and bottom joints go in opposite directions.
Because of that, attaching the ribs required putting heavy pressure on them, and since they were pretty fragile, a few broke during this process. To solve that I used a rasp to file the bottom joint of each rib so it will be easier to insert them. Finally, I added the support pieces to the ribs and started with finishing.
Before starting the project, I liked the idea of fine finishing an OSB product and found the examples we saw in class very impressive. Throughout the week, my attitude towards OSB changed, and I understood such a finish will require equipment and time I did not have.
I invested a decent amount of time in sending and used some wood-filler (sawdust and glue) to hide some of the defects in the material. Although the finish is far from perfect, the result is relatively smooth, with no sharp edges and no chips.

Conclusions
    Overall I am very proud of the final product, especially with the limitations I had. I am particularly happy that I tried to come up with creative solutions to those challenges, rather than escaping to methods that I am more comfortable with like adding material or more traditional woodworking.
    Throughout the week, I've noticed a couple of issues with my design that if addressed correctly, could save me a lot of time.
    • Consider the robustness of each part before assembly rather than the robustness of the final product alone.
      I was relatively confident that my design is strong enough but had a hard time removing and assembling the ribs that I did not expect.
    • Learn the material better! Despite Anthony's warnings, I overestimated the material durability, making the cutting and assembling process much more challenging, and the final product not as robust as I expected.
    • Consider the assembly while designing. It is important to notice that the design will allow a convenient assembly to avoid issues like the opposite directions joints I mentioned above.
Design files
Original Design
Final Design

-------

Week #6

embedded programming

Overview

That was one of the most exciting weeks for me in the class so far. I felt like I learned a lot and was very proud of the results I got at the end of it.
I wanted to build a programmed circuit that will interact with an addressable LED strip to create a game for two players.
Originally I thought of a digital tug-of-war game, in which each player presses a button to push their opponent backward.
Unfortunately, due to time constraints, I had to simplify my goals to complete the assignment on time, and my idea was to design a board that in the future will support more advanced programs, but in the meantime, will carry a simpler one.

Making The Board

I started my design from the basic SAM-D11C microcontroller circuit and only added a 10-pin connector, connected to different I/Os, ground, and 5V.
The design was simple but very flexible and can be used for all sorts of tasks depending on the program and the components that are connected to it.
I finished the design, milled, and soldered, and was finally ready to start working on the program! Little did I know that the software library I was planning to use (Adafruit Neopixel) refuses to work with the SAM-D11C and requires stronger microcontrollers. Junhong tried to help me modify the library system files and force it to support the SAM-D11C, and I found this website that described the same problem, but we quickly understood that milling a new board with a different microcontroller will be quicker and easier.

I modified my design and used the SAM-D21E, which is supported by Adafruit Neopixel and many other libraries. I also connected the empty pins on the connector to two additional I/Os and one 3.3V that may be useful in the future.
Soldering the SAM-D21E is much more challenging than other components I've used so far, but the practice during the past electronics weeks paid off and everything went as planned. This time I knew that I am done with building the board and only left with writing the program.

Programming

I started by loading the Adafruit Neopixel example code to verify my board functions correctly.
It was exciting to see the LEDs working and it felt like I finally completed this skill set of designing a board, building it, and programming it.
Additionally, I was able to properly install EDBG after having the common installation problems on mac. To do this I carefully followed the instructions on this website.

Writing The Code

I was less worried about this part of the week and playing with the code and LEDs was fun. I wanted to write a program that takes input from a button and sends 'pulses' through the LEDs strip.
I used an array of 10 integers, each of which can function as an indicator of the starting point of a pulse.
Each button press will take the first array argument that still does not represent a pulse and start incrementing it on each loop iteration. This allows me to have multiple pulses at the same time instead of one.

Additionally, I added a feature that stacks all pulses at the end of the strip until the whole strip is full, Then changes the color and sends a new pulse.
While presenting my board in class I noted that I had a bug in my software that cause the pulses to slow down if multiple pulses were sent. Thanks to Raiphy we were able to perform real-time debugging and fix the issue during the break. I also laser-cut an acrylic enclosure to make it feel more like a finished product.

I added some additional features, including another button that turns all the lights on instead of sending pulses and a long press to turn the LEDs off.

#include <Adafruit_NeoPixel.h>

#ifdef __AVR__#include <avr/power.h>
#endif
#define LEDPIN 3
#define BTN1 1
#define BTN2 2
#define NUMPIXELS 300

Adafruit_NeoPixel pixels(NUMPIXELS, LEDPIN, NEO_GRB + NEO_KHZ800);
#define DELAYVAL 0
#define NUMPULSES 10
#define PW 10

int x[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};

int buttonState = 0;
int k = NUMPIXELS + PW;
int R = random(0, 100);
int G = random(0, 100);
int B = random(0, 100);

void setup() {
    
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif

  pixels.begin();
  pinMode(BTN1, INPUT_PULLUP);
  pinMode(BTN2, INPUT_PULLUP);
  pixels.clear();
  pixels.show();
}

void loop() {
  if (digitalRead(BTN2) == LOW) {
    int c = 0;
    while (digitalRead(BTN2) == LOW) {
      if (c >= 100) {
        pixels.clear();
        pixels.show();
      }
      delay(10);
      c++;
    }
    if (c < 100) {
      for (int i = 0; i < NUMPIXELS; i++) {
        pixels.setPixelColor(i, pixels.Color(R, G, B));
      }
    }
    k = NUMPIXELS + PW;
    pixels.show();
    R = random(0, 100);
    G = random(0, 100);
    B = random(0, 100);

  }

  if (digitalRead(BTN1) == LOW) {
    while (digitalRead(BTN1) == LOW) {
      delay(10);
    }
    for (int p = 0; p < NUMPULSES; p++) {
      if (x[p] == -1) {
        x[p] = 0;
        break;
      }
    }
  }

  for (int i = 0; i < NUMPULSES; i++) {
    if (x[i] != -1) {
      pixels.setPixelColor(x[i], pixels.Color(R, G, B));
      pixels.setPixelColor(x[i] - PW, pixels.Color(0, 0, 0));
      if (x[i] < k) {
        x[i]++;
      } else {
        x[i] = -1;
        k = k - PW;
      }
    }
  }
  delay(DELAYVAL);
  pixels.show();

  if (k < PW) {
    k = NUMPIXELS + PW;
    R = random(0, 100);
    G = random(0, 100);
    B = random(0, 100);
  }
}

-------

Week #7

molding & casting

Overview

This was one of the hardest weeks for me in the class so far.
Although I started working on the assignment early in the week, I experienced many troubles with my molds and was able to start casting only the night before class.
After all, I am relatively proud of the result and happy that I could finish on time, considering the circumstances.

Design

My goal was to design a product that will utilize the main advantage of molding and casting - to produce many identical parts quickly.
I remembered seeing a kind of sculpture online that uses many similar 3D printed parts to create an art piece with a "flowing" impression.
I thought I can produce a simple version of a sculpture as such using molding and casting.
I started by designing a sigle part, which was pretty simple using the Form tool on Fusion. Then with the assembly feature, I design a final version of the assembled sculpture.

Mold Design

To derive the design of the mold from the final part shape, I sliced each part in half and placed the halves in a hollow box of the size we used for machining.
I added pegs that will allow me to assemble the molds accurately and was ready for machining. This part proved to be crucial later in the week, and the mistakes I've made here cost me a lot of time.
It seemed perfectly okay to have one type of mold for each part, and I was sure that producing two identical molds will allow me to assemble a full part.
After casting two silicon molds I found out that I was completely wrong and forgot to consider the need for mirrored molds for parts that are not fully symmetric.
Eventually, I had two perfect molds that can only produce the left half of my parts.
I accepted the fact that I need to machine a mirrored version of the mold. It was especially discouraging due to the scarcity of machine time.
Eventually, I machined a mirrored version of my mold, but due to a mismatch od the pegs I had to cast the parts in halves and glue them.

Machining & Casting

After fixing the issues with the molds I could start producing the parts. From this point, things went much more smoothly and I was able to make the parts pretty quickly and efficiently.
I used Oomoo to make the molds and dry stone to make the parts. The casting process was pretty straightforward and I enjoyed it a lot.
I used diluted dry stone to glue the pieces and to smooth the surface after gluing.

-------

Week #8

input devices

Overview

I had a lot of fun working on this week's project, and although there is some more work to be done, I am very proud of the result.
My goal for the week was to use a sensor measurement to synthesize music.
After the lecture, I was curious to work with the optical distance sensors (VL53L0X \ VL53L1X) since they seemed relatively simple to use while still producing measurements with impressive accuracy and range.
My idea was to build a rotating platform and place the sensor in front of it. That way, by placing an object on the platform, the distance measurement will change periodically, creating a different melody for different objects.

Making The Board

I used Neil's board as a reference and only changed some of the routings. That time, I didn't plan to use the board to do anything except measure distance, and unfortunately didn't add breakout pins. Because of that, I had to solder many wires to connect the speaker.

Soldering

That was the first time I used the soldering paste, and I am glad it worked on the first try. I found a lot of uncertainty in this process since it is almost impossible to know if the component was correctly placed or well-soldered.
Even after soldering the sensor, there is no way to tell if it's appropriately connected until programming the circuit.

Enclosure

To build the enclosure, I laser-cut the parts from wood and glued them all together. I aimed for a more refined design, yet the result was good and held everything together without too many visible wires. I used a DC motor with a gearbox that was wired to a potentiometer, a switch, and a 9V battery. The motor circuit was completely separate from the sensor board.
When assembling, I tried to use reliable connections, including heat shrinks for the electronics or designated grooves and holes for mechanical connections.

Programming

I started by loading the example code from Pololu's VL53L1X library.
At this point, I still didn't know if I properly soldered the sensor and was curious to test it.
Immediately after loading the software, the measurements started to go through the serial plotter! It was an exciting moment that solved the uncertainty about the board.

Making Music
I connected a piezo speaker to my board and simply used the built-in 'tone' function, with the sensor output as an argument, to play sound.
The result was noisy and not very pleasant, but it was great for a start.
I added discretization to the sensor output and associated each relevant distance range with a note's frequency in the A Minor scale.

Lastly, to address the noisiness of the sensor output, I added a moving average filter that computes the average value of the last five measurements.
Together with lowering the motor speed, this step dramatically improved the overall outcome.

Required improvements

Although the main board works well, I used too many patches to hide some significant problems. Most of them are tightly related to output devices, so I hope to solve them during output devices week! These are the main issues I need to address:

    • Unstable microcontroller startup - every time the board wakes up, it takes a few resets until it gets stable. I temporarily connected a button to the reset pin of the board, and every time I connected the board, I kept resetting it until it started working. Neil suggested a small addition to the board (can be found here) that slows down the start-up process and allows the board to stabilize.
    • A separate circuit for the motor - I used a separate 9V circuit for the motor and controlled its speed using a 200-ohm trimpot. This method dissipates a lot of energy and adds unnecessary components to the product. For next week, I will power the motor through the board and control it through the microcontroller.
    • Low speaker volume - The amplification circuit Junhong helped me to assemble was good as a patch, but I am sure that with proper connections and a better speaker, I can get better results.

-------

Week #9

output devices

Light Pong

For this week, I used my board from embedded programming week and wrote a different program to use the addressable LEDs to make a ping pong game!
Due to the flexibility of the board, it didn't require any hardware changes and was fairly easy to implement. I think this is a great example of the flexibility that comes with embedded programming.
I was extremely happy with the result and had a lot of fun making it and playing with it.

#include <Adafruit_NeoPixel.h>

#ifdef __AVR__#include <avr/power.h>
#endif

#define LEDPIN 3
#define BTN1 1
#define BTN2 2
#define NUMPIXELS 100

Adafruit_NeoPixel pixels(NUMPIXELS, LEDPIN, NEO_GRB + NEO_KHZ800);

int button = 0;
int button_p = 0;
int button1 = 0;
int button2 = 0;
int button1_p = 0;
int button2_p = 0;
int ball = 0;
bool gameOn = false;

int R_player1 = 60;
int G_player1 = 8;
int B_player1 = 0;

int R_player2 = 23;
int G_player2 = 60;
int B_player2 = 1;

int R = 200;
int G = 200;
int B = 200;

void setup() {
    #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
    clock_prescale_set(clock_div_1);
    #endif
    pinMode(BTN1, INPUT_PULLUP);
    pinMode(BTN2, INPUT_PULLUP);
    pixels.begin();

    pixels.clear();
    pixels.show();
    }

    void loop() {
    // new game starts
    int dir = random(0, 2);
    int DELAYVAL = 3500 / NUMPIXELS;

    pixels.clear();
    for (int i = 0; i <= NUMPIXELS / 4; i++) {
        pixels.setPixelColor(i, pixels.Color(R_player1, G_player1, B_player1));
    }
    for (int i = NUMPIXELS - 1 - NUMPIXELS / 4; i <= NUMPIXELS - 1; i++) {
        pixels.setPixelColor(i, pixels.Color(R_player2, G_player2, B_player2));
    }

    if (dir == 1) {
        ball = 0;
    } else {
        dir = -1;
        ball = NUMPIXELS - 1;
    }

    pixels.setPixelColor(ball, pixels.Color(R, G, B));
    pixels.show();

    while (not gameOn) {
        if (dir == -1) {
        button = digitalRead(BTN2);
        } else {
        button = digitalRead(BTN1);
        }
        if (button == LOW) {
        gameOn = true;
        ball += dir;
        }
    }

    while (gameOn) {
        button1_p = button1;
        button2_p = button2;
        button2 = digitalRead(BTN2);
        button1 = digitalRead(BTN1);

        if (dir == 1) {
        if (ball > (NUMPIXELS - NUMPIXELS / 4) - 2) {
            button = button2;
            button_p = button2_p;
        } else {
            button = HIGH;
        }
        } else {
        if (ball < NUMPIXELS / 4 + 1) {
            button = button1;
            button_p = button1_p;
        } else {
            button = HIGH;
        }
        }
        if (button == LOW && button_p == HIGH) {
        dir *= -1;
        ball += 2 * dir;
        if (DELAYVAL > 200); {
            DELAYVAL *= 0.95;
        }
        }

        delay(DELAYVAL);
        if (ball == 0) {
        gameOn = false;
        for (int i = 0; i < NUMPIXELS / 2; i++) {
            pixels.setPixelColor(i, pixels.Color(100, 0, 0));
            pixels.setPixelColor(i + (NUMPIXELS / 2), pixels.Color(0, 100, 0));
        }
        pixels.show();
        delay(3000);
        } else if (ball == NUMPIXELS - 1) {
        gameOn = false;
        for (int i = NUMPIXELS / 2; i < NUMPIXELS; i++) {
            pixels.setPixelColor(i, pixels.Color(100, 0, 0));
            pixels.setPixelColor(i - (NUMPIXELS / 2), pixels.Color(0, 100, 0));
        }
        pixels.show();
        delay(3000);
        }
        else {
        pixels.setPixelColor(ball - dir, pixels.Color(0, 0, 0));
        for (int i = 0; i <= NUMPIXELS / 4; i++) {
            pixels.setPixelColor(i, pixels.Color(R_player1, G_player1, B_player1));
        }
        for (int i = NUMPIXELS - 1 - NUMPIXELS / 4; i <= NUMPIXELS - 1; i++) {
            pixels.setPixelColor(i, pixels.Color(R_player2, G_player2, B_player2));
        }
        pixels.setPixelColor(ball, pixels.Color(R, G, B));

        ball += dir;
        pixels.show();
        }
    }
}

-------

Week #10

networking & communications

Overview

This week was a great opportunity to start working on my final project.
I wanted to start building the infrastructure for my chessboard project and aimed to create a board that handles network communication.
My goal was to be able to control the I/O pins of the microcontroller from a distant platform.

Boards

I used Neil's example board as a reference and added some breakout pins for some GPIOs. Since this was only a development board, I did not use all the GPIOs of the ESP32.
Milling and soldering were pretty straightforward.

Reset problem

I had a similar problem as I had with my input devices board. The ESP was resetting very frequently and was not stable at all.
With Junhong's help, we found that the problem was that the rise time after a reset was too short, not allowing enough time for the board to stabilize. Junhong suggested an easy fix - adding a capacitor between the reset button and the ground.
I soldered the capacitor as a patch, which immediately solved the problem.

Later I accidentally ripped the reset button and some of the copper around it, so I updated my design and remade the board.
I also used a breadboard to build a simple LED board for testing and laser cut an enclosure.

The FTDI Programmer

Due to the scarcity of FTDI cables in the shop, I used Quentin's design and built an FTDI programmer board.
I've been using it as my only programmer for a few days, and it's working perfectly.

Software

After having some positive experiences with it, I decided to use Google's Firebase as a backend service for this week and my final project. Although Firebase saves a lot of the burden, there was still a lot of software work to set up the environment and eventually create stable communication between the ESP to a web app.

The ESP side

I followed this great tutorial to set up the basic connection between my firebase project and the ESP.
Generally, I created a firebase project and configured a real-time database, which easily allowed to read and write data from different clients.
After that, I used a firebase-to-ESP32 library to build test programs that either read or write data from the database.
Eventually, I wrote a program that allowed me to control several LEDs by changing database values.
The code is repetitive and messy since it is only for testing.

#include 
#if defined(ESP32)
#include 
#elif defined(ESP8266)
#include 
#endif
#include 
#include 

// Provide the token generation process info.
#include "addons/TokenHelper.h"
// Provide the RTDB payload printing info and other helper functions.
#include "addons/RTDBHelper.h"

// Insert Firebase project API Key
#define API_KEY "AIzaSyB-fTzPgR0OgoQQ39NwGTsnaVDQ-6AWDKM"

// Insert RTDB URLefine the RTDB URL */
#define DATABASE_URL "https://m8-chess-default-rtdb.firebaseio.com/"

// Define Firebase Data object
FirebaseData fbdo;

FirebaseAuth auth;
FirebaseConfig config;

#define LED_PIN_0 25
#define LED_PIN_1 26
#define LED_PIN_2 27
#define LED_PIN_3 14
#define LED_PIN_4 12
#define LED_PIN_5 32
#define LED_PIN_6 33

unsigned long sendDataPrevMillis = 0;
int LED0;
int LED1;
int LED2;
int LED3;
int LED4;
int LED5;
int LED6;

float floatValue;
bool signupOK = false;

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

    WiFiManager wm;

    wm.resetSettings();

    bool res;
    res = wm.autoConnect("M8_Chessboard", "");

    if (!res)
    {
    Serial.println("Failed to connect");
    }

    Serial.print("Connecting to Wi-Fi");
    while (WiFi.status() != WL_CONNECTED)
    {
    Serial.print(".");
    delay(300);
    }
    Serial.println();
    Serial.print("Connected with IP: ");
    Serial.println(WiFi.localIP());
    Serial.println();

    /* Assign the api key (required) */
    config.api_key = API_KEY;

    /* Assign the RTDB URL (required) */
    config.database_url = DATABASE_URL;

    /* Sign up */
    if (Firebase.signUp(&config, &auth, "", ""))
    {
    Serial.println("ok");
    signupOK = true;
    }
    else
    {
    Serial.printf("%s\n", config.signer.signupError.message.c_str());
    }

    /* Assign the callback function for the long running token generation task */
    config.token_status_callback = tokenStatusCallback; // see addons/TokenHelper.h

    Firebase.begin(&config, &auth);
    Firebase.reconnectWiFi(true);

    pinMode(LED_PIN_0, OUTPUT);
    pinMode(LED_PIN_1, OUTPUT);
    pinMode(LED_PIN_2, OUTPUT);
    pinMode(LED_PIN_3, OUTPUT);
    pinMode(LED_PIN_4, OUTPUT);
    pinMode(LED_PIN_5, OUTPUT);
    pinMode(LED_PIN_6, OUTPUT);
}

void loop()
{
    if (Firebase.ready() && signupOK && (millis() - sendDataPrevMillis > 500 || sendDataPrevMillis == 0))
    {
    sendDataPrevMillis = millis();
    if (Firebase.RTDB.getInt(&fbdo, "/LED/0"))
    {
        if (fbdo.dataType() == "int")
        {
        LED0 = fbdo.intData();
        // Serial.print("LED 0 - ");
        // Serial.print(LED0);
        // Serial.println("");
        if (LED0 == 1)
        {
            digitalWrite(LED_PIN_0, HIGH);
        }
        else
        {
            digitalWrite(LED_PIN_0, LOW);
        }
        }
    }
    else
    {
        Serial.println("0" + fbdo.errorReason());
    }

    if (Firebase.RTDB.getInt(&fbdo, "/LED/1"))
    {
        if (fbdo.dataType() == "int")
        {
        LED1 = fbdo.intData();
        // Serial.print("LED 1 - ");
        // Serial.print(LED1);
        // Serial.println("");
        if (LED1 == 1)
        {
            digitalWrite(LED_PIN_1, HIGH);
        }
        else
        {
            digitalWrite(LED_PIN_1, LOW);
        }
        }
    }
    else
    {
        Serial.println("1" + fbdo.errorReason());
    }

    if (Firebase.RTDB.getInt(&fbdo, "/LED/2"))
    {
        if (fbdo.dataType() == "int")
        {
        LED2 = fbdo.intData();
        // Serial.print("LED 2 - ");
        // Serial.print(LED2);
        // Serial.println("");
        if (LED2 == 1)
        {
            digitalWrite(LED_PIN_2, HIGH);
        }
        else
        {
            digitalWrite(LED_PIN_2, LOW);
        }
        }
    }
    else
    {
        Serial.println("2" + fbdo.errorReason());
    }

    if (Firebase.RTDB.getInt(&fbdo, "/LED/3"))
    {
        if (fbdo.dataType() == "int")
        {
        LED3 = fbdo.intData();
        // Serial.print("LED 3 - ");
        // Serial.print(LED3);
        // Serial.println("");
        if (LED3 == 1)
        {
            digitalWrite(LED_PIN_3, HIGH);
        }
        else
        {
            digitalWrite(LED_PIN_3, LOW);
        }
        }
    }
    else
    {
        Serial.println("3" + fbdo.errorReason());
    }

    if (Firebase.RTDB.getInt(&fbdo, "/LED/4"))
    {
        if (fbdo.dataType() == "int")
        {
        LED4 = fbdo.intData();
        // Serial.print("LED 4 - ");
        // Serial.print(LED4);
        // Serial.println("");
        if (LED4 == 1)
        {
            digitalWrite(LED_PIN_4, HIGH);
        }
        else
        {
            digitalWrite(LED_PIN_4, LOW);
        }
        }
    }
    else
    {
        Serial.println("4" + fbdo.errorReason());
    }

    if (Firebase.RTDB.getInt(&fbdo, "/LED/5"))
    {
        if (fbdo.dataType() == "int")
        {
        LED5 = fbdo.intData();
        // Serial.print("LED 5 - ");
        // Serial.print(LED5);
        // Serial.println("");
        if (LED5 == 1)
        {
            digitalWrite(LED_PIN_5, HIGH);
        }
        else
        {
            digitalWrite(LED_PIN_5, LOW);
        }
        }
    }
    else
    {
        Serial.println("5" + fbdo.errorReason());
    }

    if (Firebase.RTDB.getInt(&fbdo, "/LED/6"))
    {
        if (fbdo.dataType() == "int")
        {
        LED6 = fbdo.intData();
        // Serial.print("LED 6 - ");
        // Serial.print(LED6);
        // Serial.println("");
        if (LED6 == 1)
        {
            digitalWrite(LED_PIN_6, HIGH);
        }
        else
        {
            digitalWrite(LED_PIN_6, LOW);
        }
        }
    }
    else
    {
        Serial.println("6" + fbdo.errorReason());
    }
    }
}
Web app

Since manually changing values through the firebase admin console is cumbersome and slow, I build a JavaScript test app that connects to the same database, reads and changes values, and controls the LEDs.
This tutorial describes most of the process.
I used Firebase hosting for this app, which allowed me to have an easy deployment process and a public domain.

for (let i = 0; i < 7; i++) {
    ref = database.ref("LED/" + i);
    ref.on('value', (snapshot) => {
        val = snapshot.val();
        console.log(val);
        element = document.getElementById("LED" + i)
        if (val == 1) {
            element.innerHTML = "ON";
            element.style.backgroundColor = "green";
        } else {
            element.innerHTML = "OFF";
            element.style.backgroundColor = "red";
        }

    }, (errorObject) => {
        console.log('The read failed: ' + errorObject.name);
    });
}

function tglLED(LEDid) {
    ref = database.ref("LED/" + LEDid);
    ref.get().then((snapshot) => {
        if (snapshot.exists()) {
            ref.set(snapshot.val() * -1);
        } else {
            console.log("No data available");
        }
    }).catch((error) => {
        console.error(error);
    });
}
WiFi Manager

I was proud of the result I had so far but having to hard-code the WiFi credentials every time I moved to a different network made it hard to use the board.
Originally, I thought I'll have to build a mobile app to send WiFi credentials via Bluetooth to the ESP. I was trying to find a minimalist solution for this problem, and everything seemed way too complicated.
After some research, I found this incredible library that handles this burden with a few lines of code.
I had to dive into their weirdly written code to customize the interface to a more user-friendly design, but it was worth it.
The result is a smooth, straightforward process that does not require downloading an app or any special effort from the user.
This tutorial helped me with the installation and configuration of the library.
The code for the WiFi manager is included in the ESP32-Firebase code above.

For interface week, I plan to build a chess app that controls the M8 chessboard using the same infrastructure I developed this week.

-------

Week #11

interface & application programming

For this week I developed a fully playable chess app using only JavaScript, HTML, and CSS!
Notice that the app does not work on certain browsers (like Safari) but does work on Chrome.
The app sends data to my Firebase database from week 10 and will be used as an interface for my final project.

I followed this tutorial to create the basic game logic but had to fix some bugs it had.
I also changed the UI to match popular chess apps and added all the database communication.
Finally, I used firebase hosting to allow convenient access to the app from any device connected to the internet.

-------

Week #12

mechanical machine design

Machine week was a lot of fun! Together with my lab mates, we built a cool drawing bot that process images and draw a filtered version of them.

I was curious to learn more about the mechanical aspects of building a machine and specifically designing a gantry system.
We divided the work into different tasks and assigned a few people to each of them.
I was helping with designing and cutting the parts and with assembling the gantry system.
It was a great way to see firsthand the challenges of designing a mechanical machine and the constraints that should be taken into consideration.

A major challenge we had while building the gantry was to make the wheels' mounts fit well to the aluminum extrusion. We solved it by adding fractures to the parts, to create more pressure between the wheels and the rail.
The integration between all the different groups was great, and I was proud of the overall result.

-------

Week #13

wildcard week

Although I was eager to learn how to weld, I wanted to use wildcard week for my final project. I wanted to use the CNC lathe we have at the EECS shop to make the chess pieces for my final project.

This is a great opportunity to thank Anthony for removing the dust from the old machine and setting it up for this job. Although he likes to complain about this machine, I had a great time using it and felt very comfortable working with it at the end.

I designed a chess set with a modern look to match the 'innovative' feel of the project.
The most challenging piece was the knight since it is not symmetric like the other pieces.
I designed the knight with a revolution of its head and then cut and filed it manually. I also used a Dremel to decorate the rook.

I used black wood stain to color the black pieces of the set and sanded all the pieces for a smooth finish.

This was one of the most fun weeks of the class for me!

-------