Applications and Implications
Week 17

Project Development

This week, I focused on designing, fabricating, and assembling a custom PCB. I used KiCad for schematic and PCB design, then fabricated the board using milling and laser etching, and finally assembled and tested it.

Presentation Slide

Bluetooth Speaker Test

I tested the Bluetooth speaker functionality using an ESP32. The ESP32 connects to a smartphone via Bluetooth, allowing audio playback through the speaker.

For the ESP32 to output analog audio you need to connect an I2S DAC which converts the I2S Digital Audio Signals to Analog Output and an amplifier and speaker to get the output. In the software side, we need the 'Audio Tools' and BluetoothA2DPSink Libraries

  • Audio Tools - I2S
  • BluetoothA2DPSink - Bluetooth Audio Sink

Here is the code to test the Bluetooth speaker functionality using ESP32:


#include "AudioTools.h"
#include "BluetoothA2DPSink.h"

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

void setup() {
    auto cfg = i2s.defaultConfig();
    cfg.pin_bck = 13;
    cfg.pin_ws = 14;
    cfg.pin_data = 12;
    i2s.begin(cfg);

    a2dp_sink.start("Symphoni");
}

void loop() {
}	

I tested the Bluetooth speaker with a smartphone, playing audio through the speaker. The ESP32 connects to the smartphone via Bluetooth, allowing audio playback. You can check the documetnation for Week 10: Output Devices to know more about I2S, DAC and Amplifier.

App interface

I developed a simple Android app to write the NFC tags and also to control playback. The app allows users to play/pause audio, next and previous, and adjust volume. It uses the http communication using WiFi for communication with the ESP32, which communicates with Spotify WebAPI. The app is developed using Dart(Flutter) in Android Studio.

The documentation for the app development can be seen in the Week 14: Interface and Application Programming assignment.

App and Turntable Test

I tested the app with the cardboard turntable. The turntable allows users to control playback by placing NFC tags on it. The app communicates with the ESP32 to play specific tracks based on the NFC tags scanned. I tested this in the Week 14: Interface and Application Programming assignment. I used my board that I made in the Network and Communication Week

When the NFC tag is detected by the RFID reader module, it sends the Spotify URI to the Spotify Web API which starts playback and also I have written a code to drive the motor using analogWrite.

Display Test

I tested the 2.8-inch SPI TFT display with the ESP32. The display is powered by the ESP32 and communicates via SPI.

Here, I am running the test code provided in the examples of TFT_eSPI library for 320x240. The example code 'TFT_Meters.ino' is linked here

I need to test the album cover image and URL fetching and displaying on the board.

Draft Slide and Video

I made the draft slide and video using Canva.

The slide is made using Canva, which is a user-friendly design tool that allows users to create professional-looking presentations and graphics. The slide acts just as a draft for the final presentation, showcasing the key features and functionalities of the Symphoni project.

Canva Video

The presentation slide and the presesntation video have certain criterias for the presentation.

The presentation slide should be of the dimensions 1920x1080 pixels, which is the standard size for high-definition presentations. The slide should be named "presentation.png" and should be in PNG format. The video should be of the dimensions 1920x1080 pixels, which is the standard size for high-definition videos. The video should be named "presentation.mp4" and should be in MP4 format.

Canva Slide

I used the Presentation Size preset to start designing my slide and Video. I added the rendered images to the slide and added some text about the features of the project.

For the video, I used the Canva Video preset to start designing my video. I added the rendered images to the video and added some text about the features of the project. The video is a short overview of the project, showcasing its key features and functionalities.

Canva export

There are multiple options to export, I exported the three slides as a MP4 video of 1080p(HD) resolution.

The presentation slide(presentation.PNG) and video(presentation.mp4) are placed in the root directory of the repository.

Week 18

Schedule

Day 1 (29 May)- Electronics Integration Prep + Component Testing

  • Test new speaker drivers with TPA3116D2 amplifier
  • The new speakers were noisey, therefore I decided to use my old speaker drivers 5ohm 5W.

  • Test slider pots and see if they work with amplifier's rotary pots
  • The slider pots were incompatible with the rotary potentiometers. I decided to use the rotary potentiometers which were already on the Amplifier Board. I will unsolder the potentiometers and place them on my custom board.

  • Prototype front grill - laser cut aluminum and 3D printed version
  • I tested the front grill using 3D printing using

  • Check bluetooth playback using ESP32
  • The playback controls from ESP32 didn't work out. So I am planning to control it using Spotify Web API instead

Day 2 (30 May)- Mechanical Exploration: Speaker Face, Platform and CAD Design

  • Experiment with motor-driven rotating platform
  • Sketch layout for button, encoder, speaker and display positions
  • Complete CAD

Day 3 (31 May)- Complete PCB Design

  • Complete Schematic Design
  • Comlete PCB Design

Day 4 (1 June) PCB Milling and Soldering

  • Mill the 2 PCBs
  • Assemble the PCB
  • Test the PCB Functioning

Day 5 (2 June)- Enclosure Production

  • Complete Milling of Enclosure Parts
  • Assemble the Enclosure

Day 6 (3 June)- Assembly Day

  • Assemble all components
  • Test the System
  • Finishing the looks

Day 7 (4 June)- Program the entire system

  • Spiral 1 - Programming with all basic Functions
  • Spiral 2 - Programming with all advanced Functions

Schematic Design

I designed the schematic for my final project, Symphoni, using KiCad. The schematic includes an ESP32 for Wi-Fi and Bluetooth connectivity, a 2.8-inch SPI TFT display for visual output, NFC for NFC scanning.

I took this ESP32 Autoprogrammer circuit as a reference for my schematic design from my classmate Revisankar. The circuit is designed to program the ESP32 using a USB-to-serial converter, which allows for easy programming and debugging of the ESP32 module. The circuit includes necessary components such as resistors, capacitors, and a voltage regulator to ensure stable operation during programming.

ESP32 Autoprogrammer Circuit

This is the basic schematic for the ESP32 based bluetooth speaker PCB.

Bluetooth Speaker Schematic

Main Board Schematic

The main board is also based on the ESP32, which is a powerful microcontroller with built-in Wi-Fi and Bluetooth capabilities. The schematic includes components such as a 2.8-inch SPI TFT display for visual output, an NFC module for NFC scanning, and various passive components for signal conditioning and power management.

Main Board Schematic

Components in Schematic

ESP32 Autoprogrammer with FTDI
ESP32 Basic Circuit
Power In: 5V and 12V
Regulator Circuit
Playback Control Pinout
TFT RFID Connection
Symphoni Schematic PDF

PCB Design

I designed a 2 side PCB for this as I had many peripheral conections like the RFID Reader, TFT Display, Motor, Buttons, etc. which were all further away from the mainboard.

Symphoni PCB
Symphoni PCB: Front
Symphoni PCB: Back
Symphoni PCB 3D
Symphoni PCB 3D
Symphoni PCB

Symphoni - Bluetooth Speaker Module

The bluetooth module is a part of the Symphoni project, which is a Bluetooth speaker system that allows users to play music from their smartphones or other Bluetooth-enabled devices. The module is designed to be compact and efficient, providing high-quality audio output while being easy to integrate into various projects. The module uses an ESP32 microcontroller for Bluetooth connectivity and audio processing. I have used the TPA3116D2 amplifier for driving the speakers using a PCM5102 I2S DAC module connected to the ESP32. The PCB design includes the necessary components for power management, audio output, and Bluetooth communication. The module is designed to be compatible with various speaker drivers and can be easily integrated into my final project.

PCM5102 I2S DAC Pinout
Symphoni Bluetooth Speaker Module Schematic PDF
Symphoni Bluetooth Speaker PCB
Symphoni Speaker PCB with PCM5102 I2S DAC

Playback Controls PCB

Playback Controls PCB: Front
Playback Controls PCB: Front
Playback Controls PCB: Front
Playback Controls PCB: Front
Playback Controls PCB: Front
Playback Controls PCB: Back

Power Board

MP1584 Kicad Files ZIP
Power Board PCB Schematic
Symphoni Board Schematic PDF
Power Board PCB Design
Power Board PCB Design
Power Board

CAD Design

I used Fusio360 to design the enclosure for the project.

Production and Manufacturing

CNC Machining Plywood

CNC Routed Cross Section
Ply Stack before Glueing

I used Fevicol Wood Adhesive to glue the cross-sections together and used clamps available at the lab. Initially I stuck pairs of two pieces with the help of Saheen and clamped them and left them for a few hours before releasing them from the clamps.

Ply Stack

After that I stacked them together and clamped them again and left them for a few hours before releasing them from the clamps.

Ply Stack
Ply Stack
Ply Stack after Glueing together
Front Panel Cut
Top Panel Cut

Leather Cutting

This is the video of the vegan leather cutting on the Zund Flat Bed Cutter. I used the Malai.eco Vegan Coconut Leather to finish Symphoni. I cut the leather using the Zund Flat Bed Cutter.

Malai.eco Vegan Leather
Zund Setup
Zund Setup
Zund Home
Zund Register Toolpath
Zund Thrucut Toolpath
Vegan Leather Cut

3D Printing

Outer Top Part
Small Gear
Rotary Module
Rotating Platform
Motor Mount
Display Module: Front Panel
Display Module: Back Panel
3D Prints of Display Module
3D Printed Front Grill
3D Printed Front Grill
3D Printed Buttons
3D Printed Standoffs

Laser Cutting and Engraving

I used the Trotec Laser Engraver mainly for 3 things:

  • Control Panel
  • Acrylic Record
  • Acrylic Front Screen

I engraved and cut a Matt Black 2mm Acrylic Sheet for my control panel which consisted of cutouts for the display unit, Tone Control Knobs and Playback Buttons. Below video shows a glimpse of the laser engraving and cutting of the Control Panel.

Motor Mount

I used black, blue and red acrylic sheets to form the Acrylic Records. The Records basically were designed with a lot of concentric lines mimicking the lines on record. The lines were engraved on the acrylic. They serve no functional purpose but do enhance the aesthetic appeal of the record.

Motor Mount

The record has to house a NFC Sticker Tag on it which will store the Spotify UPI. Therefore, I needed a center sticker to hide the NFC Sticker. Balasankar from the lab helped me with the design of the Sticker.

Record Sticker
Sticker PDF
Motor Mount

The front panel for the display was cut from clear acrylic according to the dimensions of the display module which I designed. The acrylic cut piece would be press fit from top of the 3D Printed Display Case.

Display Front Panel

Vinyl Cutting

For the front panel of the display unit, I wanted to have a flush screen which could blend with the LCD Display panel. For that I decide to use a Clear Acrylic and use a vinyl sticker as a placeholder to spray paint the rest of the acrylic.

The below video shows the vnyl cutting process using the Roland GS-24 vinyl cutter. I exported the design from Fusion360 as a DXF File and using Inkscape and the mods software made a cutout for the placeholder. The vinyl cutter cuts the design on the vinyl sheet, which is then applied to the acrylic panel. The vinyl sticker acts as a mask for spray painting, allowing for a clean and professional finish on the acrylic panel.

The vinyl cutter is not accurate and there is a mismatch with the cut acrylic. I didn't have time to correct the error and redesign the design. That's why I manually removed the center portion(placeholder) and stuck it on the acrylic cutout.

Acrylic with Vinyl

After sticking it, I applied Matt Black Spray paint on the acryclic cutout and left it to dry for an hour. After the paint dried up, I removed the vinyl, leaving a beautiful front panel for my display unit.

3D Printed buttons

Assembly

Display Bezel with M3 Inserts
Display Bezel with M3 Inserts
Rotary Module Placement
Rotary Module with RFID Reader
Symphoni Main Board on 3D Printed Stand
Power Board on 3D Printed Back Panel
Symphoni Bluetooth Board on 3D Printed Back Panel
Boards Assembled in Symphoni
Back Panel Screwed
Front Panel with Speakers
Front Panel with Speakers
Front Panel with Speakers
Speakers Screwed
Top Wooden Panel Assembled
Top Panel Assembled
Display module on the top panel
Top Panel Assembled
Control Panel Assembled

PRogramming

The programming was already done in the previous weeks as part of the final project


#include "AudioTools.h"
#include "BluetoothA2DPSink.h"

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

void setup() {
  auto cfg = i2s.defaultConfig();
  cfg.pin_bck = 27;
  cfg.pin_ws = 12;
  cfg.pin_data = 14;
  i2s.begin(cfg);

  a2dp_sink.start("Symphoni2");
}

void loop() {
}	

This is the fianl code that allows me to control playback using the NFC Tags and also connect to the Symphoni App to write the NFC Tags through the RFID Reader.


#include <Arduino.h>
#include <WiFi.h>
#include <SpotifyEsp32.h>
#include <WebServer.h>
#include <SPI.h>
#include <MFRC522.h>

const char* ssid = "SSID Name";  //replace with your WiFi SSID
const char* password = "SSID PAssword"; //replace with your WiFi Password

const char* CLIENT_ID = "Spotify CLIENT ID"; //replace with your Spotify Client ID
const char* CLIENT_SECRET = "Spotify CLIENT SECRET"; 	//replace with your Spotify Client Secret
const char* REFRESH_TOKEN = "Spotify Refresh Token"; //replace with your Spotify Refresh Token

#define RST_PIN 13
#define SS_PIN   5

#define motor 27

MFRC522 mfrc522(SS_PIN, RST_PIN);

Spotify sp(CLIENT_ID, CLIENT_SECRET,REFRESH_TOKEN);

WebServer server(80);

String receivedUri = "";  // <- store latest URI
bool writePending = false; // <- flag to indicate pending write


void setup() {

  pinMode(motor, OUTPUT);


  Serial.begin(115200);
  SPI.begin();
  mfrc522.PCD_Init();

  connect_to_wifi();

  server.on("/uri", HTTP_POST, handleUriPost);
  server.begin();
  Serial.println("HTTP server started");

  sp.begin();

  while(!sp.is_auth()){
    sp.handle_client();
  }

  Serial.println("Authenticated");
}

void loop() {
  server.handleClient();

  if (writePending) {
    write_nfc();
  }
  
  read_nfc();

    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();
    delay(3000);
  
}

void connect_to_wifi(){
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi...");
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.print(".");
    }
    Serial.printf("\nConnected to WiFi\n");
    Serial.println(WiFi.localIP());
}

void handleUriPost() {
  if (server.hasArg("uri")) {
    receivedUri = server.arg("uri");
    writePending = true;  // mark that we need to write
    Serial.println("Received URI: " + receivedUri);
    server.send(200, "text/plain", "URI received: " + receivedUri);
  } else {
    server.send(400, "text/plain", "Missing 'uri' parameter");
  }
}

void write_nfc(){
  Serial.println("Waiting for NFC card to write...");

    MFRC522::MIFARE_Key key;
    for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;  // Default key

    if (!mfrc522.PICC_IsNewCardPresent()) return;
    if (!mfrc522.PICC_ReadCardSerial()) return;

    Serial.print(F("Card UID: "));
    for (byte i = 0; i < mfrc522.uid.size; i++) {
      Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
      Serial.print(mfrc522.uid.uidByte[i], HEX);
    }
    Serial.println();

    // Prepare data
    byte buffer1[16];
    byte buffer2[16];
    const char* playlistID = receivedUri.c_str();
    size_t len = strlen(playlistID);

    // Fill buffer1 with first 16 bytes
    for (byte i = 0; i < 16; i++) {
      buffer1[i] = (i < len) ? playlistID[i] : ' ';
    }

    // Fill buffer2 with next 16 bytes (if any)
    for (byte i = 0; i < 16; i++) {
      byte index = i + 16;
      buffer2[i] = (index < len) ? playlistID[index] : ' ';
    }

    // Write to block 1
    byte block = 1;
    MFRC522::StatusCode status;
    status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
    if (status != MFRC522::STATUS_OK) {
      Serial.print(F("Auth failed for block 1: "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return;
    }
    status = mfrc522.MIFARE_Write(block, buffer1, 16);
    if (status != MFRC522::STATUS_OK) {
      Serial.print(F("Write failed for block 1: "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return;
    }
    Serial.println(F("Block 1 written successfully."));

    // Write to block 2
    block = 2;
    status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
    if (status != MFRC522::STATUS_OK) {
      Serial.print(F("Auth failed for block 2: "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return;
    }
    status = mfrc522.MIFARE_Write(block, buffer2, 16);
    if (status != MFRC522::STATUS_OK) {
      Serial.print(F("Write failed for block 2: "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return;
    }
    Serial.println(F("Block 2 written successfully."));

    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();

    Serial.println(F("Done writing Spotify ID!"));

    writePending = false;  // clear the flag after writing
    delay(3000);
}

void read_nfc(){
  MFRC522::MIFARE_Key key;
    for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;  // Default key

    if (!mfrc522.PICC_IsNewCardPresent()) return;  //skip everything if the card present is not new
    if (!mfrc522.PICC_ReadCardSerial()) return;    //skip everything if the card is new but the data is same

    Serial.print(F("Card UID: "));
    for (byte i = 0; i < mfrc522.uid.size; i++) {
      Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
      Serial.print(mfrc522.uid.uidByte[i], HEX);
    }
    Serial.println();

    byte buffer1[18];  // 16 bytes + 2 for CRC
    byte size = sizeof(buffer1);
    byte block;

    // Read block 1
    block = 1;
    if (!authenticateAndRead(block, buffer1, size, key)) return;

    // Read block 2
    block = 2;
    byte buffer2[18];
    size = sizeof(buffer2);
    if (!authenticateAndRead(block, buffer2, size, key)) return;

    // Combine both buffers into one string
   char context_uri[64]; // 32 + null terminator
    for (int i = 0; i < 16; i++) {
      context_uri[i] = (char)buffer1[i];
      context_uri[i + 16] = (char)buffer2[i];
    }
    context_uri[32] = '\0'; // null terminator

    // Trim trailing spaces
    for (int i = 31; i >= 0; i--) {
      if (context_uri[i] == ' ') {
        context_uri[i] = '\0';
      } else {
        break;
      }
    }
    char final_uri[80];
    snprintf(final_uri, sizeof(final_uri), "spotify:%s", context_uri);  //concatenating 'spotify:playlist:'+'context_uri' into 'final_uri'

    Serial.print(F("Context URI: "));
    Serial.println(final_uri);

response resp = sp.start_resume_playback(final_uri, 0, 0, nullptr); //send the put message to play the final_uri

if (resp.status_code == 204 || resp.status_code == 200) {
    Serial.println(F("Playback started successfully!"));
    analogWrite(motor, 40);
} else {
    Serial.print(F("Failed to start playback. HTTP code: "));
    Serial.println(resp.status_code);
}
    // Serial.print(F("Playlist ID: "));
    // Serial.println(context_uri);
    
}

bool authenticateAndRead(byte block, byte *buffer, byte &size, MFRC522::MIFARE_Key &key) {
    MFRC522::StatusCode status;

    status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
    if (status != MFRC522::STATUS_OK) {
      Serial.print(F("Authentication failed for block "));
      Serial.print(block);
      Serial.print(F(": "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return false;
    }

    status = mfrc522.MIFARE_Read(block, buffer, &size);
    if (status != MFRC522::STATUS_OK) {
      Serial.print(F("Read failed for block "));
      Serial.print(block);
      Serial.print(F(": "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return false;
    }

    return true;
}	

Testing

I tested the Symphoni project by playing music from my smartphone via Bluetooth. The NFC tags on the turntable allowed me to control playback and switch tracks.

Finishing the look

I stuck the vegan leather on the body of the Symphoni using double sided tape for the scope of the project. Mufeed, Midhun and Amal helped me to give Symphoni its finished look. Adding the leather and the 3D printed Standoffs was the highlight of project giving it that aesthetic.

Result

Symphoni
Symphoni

The below image is of our Academic Intern Kenneth from MIT who was ready to model for my project.

Symphoni with Ken
Symphoni with Me