Skip to content

Final Project

Final Project Sketch

For my final project, I am making a humidity sensored water filter. In the beginning, I didn’t know how I would do this, so I asked Chatgpt.

I prompted it to give me a basic breakdown on how to make a humidity sensored water filter. It gave me these three option on how to go about my idea.

I decided to pick the third option: “A Smart Water Filter that adjusts Based on Humidity”.

I then asked it how I would make it and the materials I would need to complete my project.

Using the component given to me by chatgpt, here is a sketch of my final project.

I created a rough model of my final project in Fusion 360. I began by sketching the profile of my model, which was a 15x7 rectangle with an arc in the center

After completing the sketch, I exited sketch mode and used the revolve tool to turn the profile into a 3D shape. Next, I used the hole tool to create a hole in the center of the object. The hole I created in the model has a 10-inch diameter and is 9 inches deep. I wanted to hollow the place I put the arch, so i created an offset plane 5 inches above the inside the bottom of the cylinder. I then created a sketch of a semi-circle that was 3.5 inches in diameters. I then used teh revolve tool which hollowed out the space where the semi-circle was. For the humidity sensor, I wanted to place it on the rim of the hole. Since I didn’t know the exact dimensions of the sensor, I approximated it by sketching a 0.5x1-inch rectangle and extruded it by -1 inch on the rim to create a small place for the sensor.

6. Electronics design

For my Individual project, I designed an acceleometer to sense the motion to blink an LED. The first step was to simulate it using a breadboard.

To check if the wiring was correct, I used a simple blink code to verify that the LED was working properly. The next step was to get the actual code that would allow the LED to blink whenever the board was rotated. First, I asked ChatGPT to provide a code that would light up an LED when the MPU6050 sensor detected rotation using a XIAO ESP32-C3. It provided me with the following code:

/*
  MPU6050 Raw


  A code for obtaining raw data from the MPU6050 module with the option to
  modify the data output format.


  Find the full MPU6050 library documentation here:
  https://github.com/ElectronicCats/mpu6050/wiki
*/
#include "I2Cdev.h"
#include "MPU6050.h"


/* MPU6050 default I2C address is 0x68*/
MPU6050 mpu;
//MPU6050 mpu(0x69);         //Use for AD0 high
//MPU6050 mpu(0x68, &Wire1); //Use for AD0 low, but 2nd Wire (TWI/I2C) object.


/* OUTPUT FORMAT DEFINITION----------------------------------------------------------------------------------
- Use "OUTPUT_READABLE_ACCELGYRO" if you want to see a tab-separated list of the accel
X/Y/Z and gyro X/Y/Z values in decimal. Easy to read, but not so easy to parse, and slower over UART.


- Use "OUTPUT_BINARY_ACCELGYRO" to send all 6 axes of data as 16-bit binary, one right after the other.
As fast as possible without compression or data loss, easy to parse, but impossible to read for a human.
This output format is used as an output.
--------------------------------------------------------------------------------------------------------------*/
#define OUTPUT_READABLE_ACCELGYRO
//#define OUTPUT_BINARY_ACCELGYRO


int16_t ax, ay, az;
int16_t gx, gy, gz;
bool blinkState;


void setup() {
  /*--Start I2C interface--*/
  #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    Wire.begin();
  #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
    Fastwire::setup(400, true);
  #endif


  Serial.begin(38400); //Initializate Serial wo work well at 8MHz/16MHz


  /*Initialize device and check connection*/
  Serial.println("Initializing MPU...");
  mpu.initialize();
  Serial.println("Testing MPU6050 connection...");
  if(mpu.testConnection() ==  false){
    Serial.println("MPU6050 connection failed");
    while(true);
  }
  else{
    Serial.println("MPU6050 connection successful");
  }


  /* Use the code below to change accel/gyro offset values. Use MPU6050_Zero to obtain the recommended offsets */
  Serial.println("Updating internal sensor offsets...\n");
  mpu.setXAccelOffset(0); //Set your accelerometer offset for axis X
  mpu.setYAccelOffset(0); //Set your accelerometer offset for axis Y
  mpu.setZAccelOffset(0); //Set your accelerometer offset for axis Z
  mpu.setXGyroOffset(0);  //Set your gyro offset for axis X
  mpu.setYGyroOffset(0);  //Set your gyro offset for axis Y
  mpu.setZGyroOffset(0);  //Set your gyro offset for axis Z
  /*Print the defined offsets*/
  Serial.print("\t");
  Serial.print(mpu.getXAccelOffset());
  Serial.print("\t");
  Serial.print(mpu.getYAccelOffset());
  Serial.print("\t");
  Serial.print(mpu.getZAccelOffset());
  Serial.print("\t");
  Serial.print(mpu.getXGyroOffset());
  Serial.print("\t");
  Serial.print(mpu.getYGyroOffset());
  Serial.print("\t");
  Serial.print(mpu.getZGyroOffset());
  Serial.print("\n");


  /*Configure board LED pin for output*/
  pinMode(D2, OUTPUT);
}


void loop() {
  /* Read raw accel/gyro data from the module. Other methods commented*/
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  //mpu.getAcceleration(&ax, &ay, &az);
  //mpu.getRotation(&gx, &gy, &gz);


  /*Print the obtained data on the defined format*/
  #ifdef OUTPUT_READABLE_ACCELGYRO
    Serial.print("a/g:\t");
    Serial.print(ax); Serial.print("\t");
    Serial.print(ay); Serial.print("\t");
    Serial.print(az); Serial.print("\t");
    Serial.print(gx); Serial.print("\t");
    Serial.print(gy); Serial.print("\t");
    Serial.println(gz);
  #endif


  #ifdef OUTPUT_BINARY_ACCELGYRO
    Serial.write((uint8_t)(ax >> 8)); Serial.write((uint8_t)(ax & 0xFF));
    Serial.write((uint8_t)(ay >> 8)); Serial.write((uint8_t)(ay & 0xFF));
    Serial.write((uint8_t)(az >> 8)); Serial.write((uint8_t)(az & 0xFF));
    Serial.write((uint8_t)(gx >> 8)); Serial.write((uint8_t)(gx & 0xFF));
    Serial.write((uint8_t)(gy >> 8)); Serial.write((uint8_t)(gy & 0xFF));
    Serial.write((uint8_t)(gz >> 8)); Serial.write((uint8_t)(gz & 0xFF));
  #endif


  /*Blink LED to indicate activity*/
  blinkState = !blinkState;
  digitalWrite(D2, blinkState);
}

When I put this code into my board the LED did not light up at all. I then went back into Chatgpt, and inputed both the failed code and the blink code to get as detailed as possibly. Here is the link to the entire process.

This is the final working code:

#include <Wire.h>     // Standard I2C library
#include "I2Cdev.h"   // Required by MPU6050 library
#include "MPU6050.h"  // MPU6050 library by Electronic Cats/jrowberg


/* MPU6050 default I2C address is 0x68 */
MPU6050 mpu;
//MPU6050 mpu(0x69);      // Use if AD0 pin is HIGH
//MPU6050 mpu(0x68, &Wire1); // Use if using a non-default Wire interface


// Define the LED pin (as specified, D2 for XIAO ESP32-C3)
const int ledPin = D2; // Or just 2 if D2 isn't defined in your board package


// Define the threshold for X-axis acceleration
// --- YOU WILL LIKELY NEED TO TUNE THIS VALUE ---
// Observe the 'ax' values printed to the Serial Monitor when the sensor is still
// and when you move it in the way you want to detect. Pick a value slightly
// above the resting noise level but below the movement level you want to trigger the LED.
// Raw values range roughly from -17000 to +17000 for +/-2g sensitivity (default).
const int accelThreshold = 15000; // Example threshold, adjust as needed! //orginally 4000 set to  3000


// Variables to store sensor data
int16_t ax, ay, az;
int16_t gx, gy, gz;


void setup() {
  // Initialize Serial communication for debugging
  Serial.begin(115200); // Use a common baud rate like 115200
  while (!Serial); // Wait for Serial port to connect (optional, good practice)


  Serial.println("Initializing I2C devices...");


  // Initialize I2C communication
  // For XIAO ESP32-C3, default SDA is D4, SCL is D5.
  // Wire.begin() typically uses the default pins.
  // If your MPU6050 is connected to different pins, specify them:
  // Wire.begin(SDA_PIN, SCL_PIN); e.g. Wire.begin(D4, D5);
  Wire.begin();


  // Initialize MPU6050
  Serial.println("Initializing MPU6050...");
  mpu.initialize();


  // Verify MPU6050 connection
  Serial.println("Testing MPU6050 connection...");
  if (mpu.testConnection()) {
    Serial.println("MPU6050 connection successful");
  } else {
    Serial.println("MPU6050 connection failed! Check wiring.");
    // Halt execution if the sensor isn't found
    while (1);
  }


  // (Optional but recommended) Load calibration offsets if you have them
  // Use a separate sketch (like MPU6050_Calibration) to find these values
  // Serial.println("Applying MPU offsets (if any)...");
  // mpu.setXAccelOffset(YOUR_OFFSET_X);
  // mpu.setYAccelOffset(YOUR_OFFSET_Y);
  // mpu.setZAccelOffset(YOUR_OFFSET_Z);
  // mpu.setXGyroOffset(YOUR_GYRO_OFFSET_X);
  // mpu.setYGyroOffset(YOUR_GYRO_OFFSET_Y);
  // mpu.setZGyroOffset(YOUR_GYRO_OFFSET_Z);


  // Initialize the LED pin as an output
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW); // Start with the LED off


  Serial.println("Setup complete. Reading sensors...");
  Serial.println("Move the sensor along the X-axis to trigger the LED.");
  Serial.println("Raw Accelerometer readings (ax, ay, az):");
}


void loop() {
  // Read raw accelerometer and gyroscope data
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);


  // Print the raw accelerometer values for debugging/tuning
  Serial.print("ax: "); Serial.print(ax);
  Serial.print("\tay: "); Serial.print(ay);
  Serial.print("\taz: "); Serial.println(az);


  // --- LED Control Logic ---
  // Check if the absolute value of X-axis acceleration exceeds the threshold
  if (abs(ax) > accelThreshold) {
    // If acceleration is high enough, turn the LED ON
    digitalWrite(ledPin, HIGH);
    // Optional: Print a message when triggered
    // Serial.println("X-Axis Threshold Exceeded - LED ON");
  } else {
    // Otherwise, turn the LED OFF
    digitalWrite(ledPin, LOW);
  }


  // Add a small delay to prevent overwhelming the Serial portr
  // and allow time for sensor readings to stabilize slightly.
  // Adjust as needed, but avoid long delays for responsiveness.
  delay(50);
}  

Here is the video of my board correctly working:

The step was to create a skematic of the board I am going to mill.

In the symbol library, I added these symbols and their correct footprints

  • Module_XIAO-ESP32C3 ----- fab:SeeedStudio_XIAO_ESP32C3
  • LED ----- LED_SMD:LED_1206_3216Metric
  • Conn_01x08_Pin ----- Connector_Molex:Molex_KK-396_A-41791-0008_1x08_P3.96mm_Vertical
  • R_1206 ----- fab:R_1206

This is what the final schematic looked like:

I then connected each component in the PCB simulator

I then soldered my board and added all the necessary components.

I uploaded the working code onto my board and hereis the final result:

Reflection

This week gave me experience with input devices and interpreting both analog and digital signals. In the group assignment, I worked on a capacitive touch sensor. I watched how touch events produce clear HIGH/LOW digital outputs and using a voltmeter to confirm the signal behavior. For the individual assignment, I used an MPU6050 accelerometer with the XIAO ESP32-C3 to blink an LED when motion was detected. The process involved debugging initial code issues, tuning the acceleration threshold, and interpreting raw sensor data. Through trial and error, I refined the code until it responded accurately to movement. Creating the schematic, routing the board, and successfully uploading the final working code made the entire process come full circle. Overall, this week improved my confidence in integrating sensors, reading real-time data, and building functioning embedded systems from the ground up.

Here is the link to all the files for this week.

Gantt Chart

Bill of material


Last update: May 22, 2025