Principles and Practices

  • Plan and sketch a potential final project

This is where I will start defining my final project idea and start to get use to the documentation process.


Initial Project Idea - Week 1

As my final project for Fab Academy, I'm designing my own personal versatile angle-adjustable lap table specifically. The surface is designed in such a way that has steppers for the laptop to be angle as desired and most comfortable. During prolonged use, an integrated cooling system beneath the surface will help maintain acceptable safe temperatures for the laptop. This will be done using a microcontroller, most likely ESP32-s3, connected to a temperature sensor (like lm35-input device). The sensor will sense when temperature of the laptop's CPU goes above a certain threshhold (for heavy load: 80°C)and send a warning to an embedded capacitive touch screen to turn on the fan. A separate tablet holder for increased productivity and integrated USB ports for device charging will be also parts of the design. My laptop measures 360mm (length) × 240mm (width). The table measures 800mm (length) × 400mm (width). For ergonomic support, there is an 8 cm wrist cushion included. The project's goal is to provide me with a work environment solution by integrating comfort, technology, and utility, especially in the days where I don't feel like going out of my bed, yet still wanting to be productive and completing my tasks.

Rough Sketch for Project Idea

Project Sketch

Initial Research

Research on Hardware possibility - Week 3

A good source to acquire datasheets from: alldatasheet

1. Temperature Monitoring and Control:
Temperature Monitoring and Control:

Create firmware using the Arduino IDE that utilizes an ADC channel to read the LM35 sensor. Since the ESP32 has a **12-bit ADC** (4096 levels) and typically operates with **Vref = 3.3V**, the raw ADC reading needs to be converted to a meaningful temperature value.

However, due to the ESP32's **non-linear ADC response**, the LM35 sensor may require a voltage offset correction. A **diode-based offset circuit** (e.g., two diodes in series) is recommended to shift the sensor output voltage into a more linear ADC range.

Corrected Temperature Formula:
Temperature (°C) = ((ADC_Value * Vref) / ADC_Max - V_offset) * 100

Where:

  • Vref = 3.3V** (ESP32 reference voltage)
  • ADC_Max = 4095> (12-bit ADC resolution)
  • V_offset ≈ 1.4V (using two diodes in series, if required for correction)

source:

LM35 Sensor Interfacing with ESP32 - Electronic Wings

Set a threshold temperature (resource: Normal CPU Temperature); if the measured temperature exceeds this threshold, adjust the PWM duty cycle to increase fan speed automatically and display notification on the display.

Control PMW fan

Create PWM signals for every fan using the ESP32's PWM capabilities.

To optimize cooling, map the temperature data to a PWM duty cycle. For instance, if the temperature is extremely high, set the duty cycle close to 100%.

Potential Hardware Components

Research on PCB Production - Week 6

For this week, working on KiCad for the first time was very frustrating. First, I started sketching the schematic in order for the PCB to be produced. I read through the datasheets of all the possible components. I learned that a mosfet is most likely needed. A Mosfet is a shortcut for Metal Oxide Semiconductor Field-effect Transistor (MOSFET, MOS-FET, or MOS FET), which is N−channel transistor with an insulated gate where the voltage regulates the conductivity of the device. Hence, it will be used as a low-side switch to drive the fans (its gate driven by a Pico GPIO, drain connected to the FAN, and source to GND). Moreover, to protect against inductive voltage spikes when the fans are turned off, a Diode is added. A diode is Diodes have polarity, determined by an anode (positive lead) and cathode (negative lead) and it mostly allow current to flow only when positive voltage is applied to the anode.

Stress Test Laptop's CPU

Using Prime95, I conduct a stress test for the CPU to determine how hot my laptop gets. A stress test is a process that deliberately pushes the computer system beyond its normal operational capacity to evaluate its stability and identify its weaknesses. To monitor CPU temperatures during the stress test, I installed HWMonitor This will help me determine more precisely what kind of fans I will eventually need and where to mount the temperature sensors for the most accurate temperature reading when the laptop is stressed while using multiple softwares simultaneously that require high CPU performance. From the Prime95 options, I selected torture test and I ticked on Small FFTs to push the laptop to the limits. Then, Pressed ok and ran the test. I switch to HWMonitor window to monitor the temperature. I found out that P-cores (performance Cores) max temperature to be 69°C, and the E-Cores (Efficiency Cores) Max Tempemperature to be 66°C. This means that my laptop's CPU is still in the safe zone; remaining under 70°C. However, the heat on the bottom suface is still visible and working with softwares such as Fusion360 requires constant monitoring and controlling to keep temperature under 70°C and to prevent thermal throttling to maintain standard performance.
Prime95
HWMonitor
Furthermore, I will try to do a paid benchmark test for the overall state of the laptop under stress more accurately. Moreover, I heard there is a thermal camera in our fablab that I could use to capture visually where the hot spots of my laptop surface. I will need to investigate more about that

Exploring unfied Power Supply with Voltage Regulation

When designing an electronic system with multiple voltage requirements, such as powering a microcontroller, temperature sensors, DC cooling fans, and OLED display,it is essential to use an efficient power distribution method. One common approach is using a single power supply with a voltage regulator to provide multiple output voltages (e.g., 12V for fans, 5V for the microcontroller, and 3.3V for sensors). This method ensures a compact, efficient, and cost-effective setup, decreasing the need for several power sources and avoiding complex wiring. However, different components in the system require different voltages. For instance:
  • 12V → Required for the fans.
  • 5V → Used for ESP32 or Rasberry Pi Pico microcontrollers.
  • 3.3V → Needed for sensors, and the display.

How a Voltage Regulator Works

The most commonly used regulators include:

  • Linear Voltage Regulators (e.g., LM317, 7805, 1117-3.3V): simple mechanism where they use a transistor controlled by a negative-feedback circuit to produce a specified output voltage, but less efficient as they dissipate excess energy as heat.
  • Switching Voltage Regulators (e.g., Buck Converters, LM2596 ): consist of a power switch, an inductor, and a diode to transfer energy from input to output. They are highly efficient since they convert energy with minimal heat loss. This is usually done by storing and releasing energy through an inductor.

Example Circuit Design

A power distribution system using a single 12V power adapter and voltage regulators: (See Link)
                        - 12V Power Input
                            ├── 12V DC Fan (Direct Connection)
                            ├── Step-Down Regulator LM2596 (Buck Converter) → 5V (Microcontroller and sensors)
                            ├── From the Pi Pico W → 3.3V (OLED display)
                        
Project Sketch 2

2D and 3D Modeling

Designing LapTable Prototype for CNCing - Week 7

Table Prototype
For this week, I designed a prototype for my table. Since I am not decided yet on the hardware components, I desgined the table without any pockets for the electronics to be inserted in. However, for the adjusting angle mechanism, I desgined rod and slots for the rod to go in and I added Revolute joints to simulate the real movement of this part. For the pivot point, I desgined for now just a simple wooden dowel, since the challenge for the week was to avoid using screws or glue. In order to sync the movement of the rod with the movement of the table middle section surface, I used Motion Link. Unfortunately, this week was full of unpredictable incidents that hindered the cutting process. Hence, the production of the prototype is still to be continued!

Electronics Production - Week 8

For this week, I produced the PCB that I am planning to implement in my final project. As a microcontroller I am using the Raspberry Pi Pico:. I added few extra pinheaders in case I decide later to integrate few hardward components onto my PCB. Furthermore, I soldered the capacitors that will be necessary to regulate the voltage using Linear Voltage Regulator DPAK. This will ensure providing stable power to the fan (12v), as well as the microcontroller (5v). However, I still need to procur the temperature sensors LM35 temperature sensor, the Mosfet and the diode for the PWM control of the fan. Moreover, the fan and the OLED display still have to be ordered in order to test the the functionality of the circuit as a first step before adding any modifications onto it.
PCBsoldered

PCB Soldered and Tested - Week 9

Input Device

DS18B20 Sensor Test with my personal PCB

I linked the DS18b20 to pinheaders I soldered on the board I produced in Week8- Electronics Production. One pin is connected to common GND, one pin is connected to 5V, and the third one is connected to GPIO 27 (output). In ArduinoIDE, I ran the code example single from the library and I read the temperature on the serial monitor in Celsius degrees.I figured it was roughly around room temperature (~24°C).
SerialMonitorDS18B20

Stress and Benchmark Test

However, in order to push the laptop to its limit, Using Prime95, I conduct a stress test for the CPU to determine how hot my laptop gets. A stress test is a process that deliberately pushes the computer system beyond its normal operational capacity to evaluate its stability and identify its weaknesses. This will help me determine more precisely what kind of fans I will eventually need and where to mount the temperature sensors for the most accurate temperature reading when the laptop is stressed while using multiple softwares simultaneously that require high CPU performance. From the Prime95 options, I selected torture test and I ticked on Small FFTs to push the laptop to the limits. Then, Pressed ok and ran the test. I repeated the same process but with a throughput benshmark test.
TortureTest2
Benchmarktest
To amplify even more, I placed my setup under the sun and fixated the temperarure sensor on the laser cutter under the laptop, where the CPU is placed (middle upper section of the laptop's bottom surface)
Laptopundersun
Laptopundersun2
Reading the temperature on the Serial Monitor, I noticed how it raised up to 33°C. This means that the sensor in fact detected the impact of the sun, as well as the stress and benchmark test on the heat of the laptop's CPU.
Tempertauresensorunderlaptop

Output Device - Week 10

Testing with DC 12V fan and the Voltage Regulator

To verify the voltage regulator is soldered properly and regulates the desired voltages: one leg has 12v coming in and the other leg has 5v going out, a multimelter was used.
It worked! :) We can see how our fan makes the receipt paper fly!

Progress on Final Arduino Code - Week 11

Testing the Fan's Threshold for PWM Duty Cycle

To provide the 12 v that the fan requires, I used the powerbench and connected it to the terminal connector dedicated for it in my designed PCB (see Week 6 - Electronics Design) In order to test what is the minimum Threshold the fan can detect for PWM and find out the right mapping range, the example AnalogInOutSerial was used. Since only the analogOutPin is our interest, I changed this to pin 16, which is the pin where the mosfet-fan circuit are connected. Then, I varied the outputValue from 80 all the way to 230 to check when the fan starts to respond. The result was the minimum threshold the fan can respond for PWM was 230. My final code was modified accordingly.


                                    /*
  Analog input, analog output, serial output - Modified

  Reads an analog input pin, maps the result to a range from 0 to 255 and uses
  the result to set the pulse width modulation (PWM) of an output pin.
  Also prints the results to the Serial Monitor.

  The circuit:
  - potentiometer connected to analog pin 0.
    Center pin of the potentiometer goes to the analog pin.
    side pins of the potentiometer go to +5V and ground
  - LED connected from digital pin 9 to ground through 220 ohm resistor

  created 29 Dec. 2008
  modified 9 Apr 2012
  by Tom Igoe

  This example code is in the public domain.

  https://docs.arduino.cc/built-in-examples/analog/AnalogInOutSerial/
*/

// These constants won't change. They're used to give names to the pins used:
const int analogInPin = A1;  // Analog input pin that the potentiometer is attached to
const int analogOutPin = 16;  // Analog output pin that the Mosfet is attached to

int sensorValue = 0;  // value read from the pot
int outputValue = 0;  // value output to the PWM (analog out)

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
}

void loop() {
  // read the analog in value:
  sensorValue = analogRead(analogInPin);
  // map it to the range of the analog out:
 // outputValue = map(sensorValue, 0, 1023, 0, 255);
  outputValue =230; // to test the Fan's threshold for PWM 

  // change the analog out value:
  analogWrite(analogOutPin, outputValue);

  // print the results to the Serial Monitor:
  Serial.print("sensor = ");
  Serial.print(sensorValue);
  Serial.print("\t output = ");
  Serial.println(outputValue);

  // wait 2 milliseconds before the next loop for the analog-to-digital
  // converter to settle after the last reading:
  delay(2);
}


Final Code Draft Explanation

First, finding the most accurately calibrated library for the DS18B20 temperature sensor reading was necessary. DallasTemperature library. I downloaded the library and integrated it to my code. However, when trying to increase the temperature with body temperature by holding the sensor, the sensor was responding very slowly and the temperature raised up to only 27 °C. Then, We tried out few more libraries for the DS18B20 temperature sensor and most of them had compatibility issues with Pi Pico W. Finally, reading through this link, we figured that microDS18B20 library was a referred to as a more accurate updated library. Therefore, I went and downloaded the library from the library manager.
microDSBTemp
To test the library's compatibility with Pi Pico W, we tried out one pin one sensor example. Finally, it worked and the temperator sensing percision was improved.
Using the OneWire protocol and the microDS18B20 library for the temperature sensors, this code measures the temperatures of two DS18B20 sensors and averages them to operate a DC fan and light up an LED. With defining spacing for clarity, it sets up the default I2C bus to activate an OLED display that shows the fan status and mean temperature. It requests both sensors for their temperature measurements, calculates the mean, and outputs the results to the Serial Monitor. In order to control the fan status, a temperature threshold is set to 23°C. If the average temperature is below 23°C, the fan stays off; when the temperature rises to 23°C, the fan starts at 20% speed. The fan speed rises by an extra 20% for each 1°C increment above 23°C (i.e., it becomes 40% at 24°C, 60% at 25°C, 80% at 26°C, and 100% at 27°C or higher). Additionally, based on the previous test findings, the PWM output is mapped to the range of 230 to 255. This ensures that even at the lower end of the speed range, there is sufficient voltage/current to properly start the DC fan. the OLED display, the mean temperature is always displayed on the first line. on the second line, the fan status is displayed; if the fan is off, it shows just Fan:OFF. However, if the fan is on; it shows for the first 2 seconds Fan:ON, then it disappears and Speed:(value) % appears according to the mapping in the code!

                                            /*
                                            The following code is a draft for my final project:
                                            - Drive a fan based on the mean temperature recorded by two DS18B20 temperature sensors 
                                            - To control the speed of the fan, it is mapped to the PWM range of 230 to 255, where a minimum temperature threshold is set and an increment of 20% speed increase corresponds to 1°C temperature increased
                                            - Information about fan status and mean temperature is shown on an OLED01.3 display 
                                          */
                                            
                                                #include 
                                                #include 
                                                #include 
                                                #include 
                                                
                                                // I2C OLED Setup 
                                                #define I2C_ADDRESS 0x3C  
                                                #define SCREEN_WIDTH 128
                                                #define SCREEN_HEIGHT 64
                                                
                                                // Initialize the OLED display using the default I2C bus (Wire)
                                                Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire);
                                                
                                                // DS18B20 Temperature Sensors 
                                                // Sensors are connected to GPIO26 and GPIO27
                                                MicroDS18B20<26> sensor1;
                                                MicroDS18B20<27> sensor2;
                                                
                                                // LED and Fan Definitions 
                                                #define LED_PIN 22   // LED to indicate temperature threshold
                                                #define FAN_PIN 16   // DC fan controlled via PWM
                                                
                                                // Temperature thresholds for fan control
                                                const float tempThreshold = 23.0;  // Fan starts running at 23°C
                                                const float maxTempForFan = 27.0;    // Fan reaches 100% speed at 27°C
                                                
                                                // Global variable to track when the fan turns on (in milliseconds)
                                                unsigned long fanOnStartTime = 0;
                                                
                                                void setup() {
                                                  Serial.begin(9600);
                                                
                                                  // Initialize I2C bus
                                                  Wire.begin();
                                                
                                                  // Initialize the OLED display; if not found, pause execution
                                                  if (!display.begin(I2C_ADDRESS, true)) {  
                                                    Serial.println(F("OLED not found"));
                                                    while (1);
                                                  }
                                                
                                                  // Configure the LED and Fan pins as outputs
                                                  pinMode(LED_PIN, OUTPUT);
                                                  pinMode(FAN_PIN, OUTPUT);
                                                
                                                  // Display a startup message
                                                  display.clearDisplay();
                                                  display.setTextSize(2);
                                                  display.setTextColor(SH110X_WHITE);
                                                  display.setCursor(0, 10);
                                                  display.println("Starting...");
                                                  display.display();
                                                  delay(2000);
                                                }
                                                
                                                void loop() {
                                                  // Request temperature readings from both sensors
                                                  sensor1.requestTemp();
                                                  sensor2.requestTemp();
                                                  
                                                  // Wait for conversion.
                                                  delay(1000);
                                                  
                                                  // Variables to hold temperature values and sensor status
                                                  float temp1 = 0, temp2 = 0;
                                                  bool sensor1_ok = false, sensor2_ok = false;
                                                  
                                                  // Read sensor1
                                                  if (sensor1.readTemp()) {
                                                    temp1 = sensor1.getTemp();
                                                    sensor1_ok = true;
                                                  } else {
                                                    Serial.println("Error reading sensor1");
                                                  }
                                                  
                                                  // Read sensor2
                                                  if (sensor2.readTemp()) {
                                                    temp2 = sensor2.getTemp();
                                                    sensor2_ok = true;
                                                  } else {
                                                    Serial.println("Error reading sensor2");
                                                  }
                                                  
                                                  // Validate sensor data
                                                  bool validData = sensor1_ok && sensor2_ok;
                                                  float meanTemp = 0;
                                                  
                                                  if (validData) {
                                                    meanTemp = (temp1 + temp2) / 2.0;
                                                    Serial.print("t1: ");
                                                    Serial.print(temp1);
                                                    Serial.print(" C, t2: ");
                                                    Serial.print(temp2);
                                                    Serial.print(" C, Mean: ");
                                                    Serial.print(meanTemp);
                                                    Serial.println(" C");
                                                  } else {
                                                    Serial.println("Cannot compute mean: one or more sensor readings failed");
                                                  }
                                                  
                                                  // Variables for fan control
                                                  bool fanOn = false;
                                                  int fanSpeedPercent = 0;
                                                  int pwmValue = 0;  // PWM value (0 - 255)
                                                
                                                  // Only control the fan if sensor data is valid
                                                  if (validData && (meanTemp >= tempThreshold)) {
                                                    digitalWrite(LED_PIN, HIGH);  // Turn on LED
                                                
                                                    // Calculate fan speed percentage based on temperature between threshold and maxTempForFan
                                                    if (meanTemp >= maxTempForFan) {
                                                      fanSpeedPercent = 100;
                                                    } else {
                                                      fanSpeedPercent = (int)(((meanTemp - tempThreshold) / (maxTempForFan - tempThreshold)) * 100);
                                                    }
                                                    
                                                    // Map the fan speed percentage to PWM value in the range 230 to 255
                                                    pwmValue = map(fanSpeedPercent, 0, 100, 230, 255);
                                                    analogWrite(FAN_PIN, pwmValue);
                                                    fanOn = true;
                                                    
                                                    // Record fan activation time if it just started
                                                    if (fanOnStartTime == 0) {
                                                      fanOnStartTime = millis();
                                                    }
                                                  } else {
                                                    digitalWrite(LED_PIN, LOW);   // Turn off LED
                                                    analogWrite(FAN_PIN, 0);        // Turn off fan
                                                    fanSpeedPercent = 0;
                                                    fanOnStartTime = 0;
                                                  }
                                                  
                                                  // Update the OLED display
                                                  display.clearDisplay();
                                                  display.setTextSize(2);
                                                  display.setCursor(0, 0);
                                                  
                                                  if (validData) {
                                                    // First line: Mean temperature with unit Celcius degrees
                                                    display.print("Mean:");
                                                    display.print(meanTemp, 1);
                                                    display.print("C");
                                                  
                                                    // Second line: Fan status/speed
                                                    display.setTextSize(2);
                                                    display.setCursor(0, 35);
                                                    if (fanOn) {
                                                      // For the first 2 seconds, display "Fan: ON"
                                                      if (millis() - fanOnStartTime < 2000) {
                                                        display.println("Fan: ON");
                                                      } else {
                                                        display.print("Speed:"); //Afterwards, show the fan speed percentage
                                                        display.print(fanSpeedPercent);
                                                        display.println("%");
                                                      }
                                                    } else {
                                                      display.println("Fan: OFF");
                                                    }
                                                  } else {
                                                    display.println("Sensor error");
                                                  }
                                                  
                                                  display.display();
                                                
                                                  delay(1000);
                                                }                                                                                                                               

                        
                    

Reflection and Struggles - Week 11

Connecting my Pi Pico and uploading the code was quite a challenge this week. I experimented with different libraries and, after thorough testing, discovered that the MicroDS18B20 library offers a more precise temperature measurement compared to the DallasTemperature library. This precision is crucial for accurately controlling the fan speed once I have my setup fully ready. Moreover, the Pi Pico was repeatedly stuck in the boot mode port UF2 Board, and while uploading the code, it indicated that the port was not connected, without giving me the option to change the port to COM7 or COM8, which is usually the port name when data was being transmitted. Therefore, I had to reset it using the BOOTSEL button multiple times, maneuver by first uploading a simple sketch, then my actual code to refresh the wireframes.

Assembling LapTable 1.0 Prototype - Week 12

I’m satisfied with the adjustable‐angle mechanism in the midsection. However, one major lesson I learned is never to cut pieces from the same assembly on two different CNC machines: they’ll have different tolerances and deviations, which makes fitting everything together much harder. As a result, I ended up using chisels and files to get all the pieces to fit properly. Although I originally designed everything to require no screws or glue, the dimensional variations—and the need for stability, especially in the legs—forced me to use a little glue and a few screws. For my final table, I definitely want to redesign the legs so they fold; that way I can store the table with maximum space efficiency. I also plan to allow more time for multiple iterations and to incorporate my instructor’s feedback several times before cutting the final design.
tabelprototypeangle
tableprototypeshot

Work Completed Up to the Midterm

I tested and experimented with the following aspects of my Lap Table:

  • PCB design and production: created a board to control the fan (output device) using temperature-sensor readings (input device).
  • Lap Table prototype 1.0: cut the first design and evaluated it.
  • Temperature-benchmark tests: determined the threshold for driving the fan in Arduino IDE.
  • DS18B20 sensor tests: verified the temperature sensor with a test fan.
  • PWM mapping: mapped temperature values to the fan-speed range.

Work Remaining After the Midterm

I still need to complete the following tasks for my Lap Table:

  • Redesign the Lap Table: improve stability and add new features.
  • Real-fan testing: map PWM values from the DS18B20 sensor to the speed of my 12 V DC fan.
  • Power-supply testing: evaluate a USB-PD (Power Delivery) trigger module with the electronics setup.
  • Cable management and electronics organizer: design and 3-D-print pieces to be integrated into the table, keeping ergonomics in mind.
  • Final evaluation: critically assess strengths and weaknesses to inform future projects.

Materials

Qty Description Price Link
one Raspberry Pi Pico W 6.99€ Raspberry Pi Pico W
one Mosfet SOT-23 0.37€ Mosfet
two Option1: Temperature Sensors LM35 5.50€ Temperature Sensor LM35
two Option2: DS18B20 Temperature Sensor Module 2,40 € DS18B20 shield
one Diode SOD123 0.25€ SOD123 Diode
one 60x60x25mm / 12V / 0,026A Fan 2.60€ DC 12V Fan
one USB PD (Power Delivery) trigger module 11.20€ USB PD (Power Delivery) trigger module

Files

  • Final Design Files
  • .f3d
  • Final Code Files
  • .ino