Washer Dryer Timer
Devin Chang
Devin Chang
Perspective view of the washer-dryer timer with no power connected, and the accelerometer placed on the demo washing machine
My project is a timer that helps me keep track of how long my laundry cycles take and a remote indicator that tells me when my laundry is done. It consists of an LCD display that shows a timer and a visual indicator for when a cycle is running or complete. The two corresponding buttons allow me to start a cycle timer and reset it after a cycle has completed.
Overall Photo of the project excluding the demo washing machine
Photo of the demo washing machine
Photo of the lid of the machines being removed to show the electrical components inside
Close up detail of the electrical components in the machine
In this video, I show the how my demo washing machine works. There's an arduino inside the box soldered to a latching push button switch that when pressed would power an servo motor that jitters the accelerometer platform left and right. This simulates the vibrations of the washing machine using quick velocity changes.
In this video, I show how to operate my washing machine timer with my demo washing machine. Both my machine and the demo washing machine are powered by my laptop. When powered, the LCD display indicated "Press to Start Cycle". When I pressed the start cycle button, the LCD display indicated "Ready to Start Awaiting Move". Then I pressed the button to power on the demo washing machine, which changes the LCD display to "Cycle Running" and a count-up timer. I manually powered off the demo washing machine, and the LCD finally displayed a flashing "Cycle Completed" and the total time of the cycle. I went ahead and pressed the reset button, which resets back to the "Press to Start Cycle" display, and then did another cycle.
Wiring out the prototype. One receiver and one transmitter arduino both with capacitors
Result of 2 hours of trying the debug the radio communication between the two Arduinos and then 2 hours of debugging with Zach. (Still didn't work)
Done wiring and coding the: Accelerometer, LCD display and replaced radio communicators with serial communication between the Arduinos
After assembling simple cardboard cutout boxes, and finished the code to connect the accelerometer to the LCD display. Also made a really quick washing machine to demo my project
The initial goal was to establish wireless communication between two Arduinos to remotely transmit accelerometer data to the LCD display. At first, I finished connecting the hardware based on the tutorial, then I used Copilot to quickly prototype some code that would send accelerometer readings from the transmitting Arduino to the receiving Arduino. However, the serial monitor did not indicate any data being transmitted.
To isolate the issue, I wrote a simple debugging sketch that would serial print "Hello World" on the receiver’s monitor. This also failed, which made me think that it might be a hardware issue. I want to make sure that the problem wasn't software, so I tested the built-in RF24 example from the Arduino IDE, but it also didn’t function as expected.
Now I suspect the issue stems from the hardware, so I replaced all serial communication components and meticulously rechecked the wiring multiple times. Three separate rebuilds later, there was no success. I scheduled a troubleshooting session with Zach to get a second perspective.
Together, we:
- Replaced all wiring using distinct colors to eliminate confusion.
- Retested the RF24 example with fresh components.
- Powered the Arduinos from separate sources to rule out power-related issues.
- Tried several alternative RF24 test codes sourced from GitHub and online forums.
Eventually, we observed that the receiver says that it is detecting incoming signals, but the transmitter consistently failed to confirm successful data transmission. This pointed to a persistent issue on the transmission side and possibly also the receiving side. Ultimately, we decided that it is in my best interest to ditch the radio communication component and replace it with serial communication.
One very interesting suggestion that I got from guest 2 was putting the accelerometer on a springy platform, which would exaggerate the vibration of the washing machine. I thought that it was a great idea, as a caveat to my demo washing machine is the exaggerated movements, which might not pick up as well on a vibrating washing machine. Guest 3 commented that they liked the form and the choice of using cardboard to enclose my electrical components. I sort of disagree in the sense that I would much prefer to use a more sturdy material like plywood or acrylic if I were to improvise it, and right now, they are a little too large and bulky.
I am satisfied with the result I achieved with my project. The goal was to help me time how long my laundry machine cycles run, and remotely tell me when a cycle is completed, and it did so successfully. However, it would've been a lot nicer if I had gotten the radio communication to work, which would have eliminated all the unnecessary and long wiring between the Arduinos. I also wished that I had more time to work on the form factor of the project, maybe by laser-cutting the containers to make it look less prototypy
I've found that sometimes electrical components don't work the way you would expect them to. I got too caught up in troubleshooting and spending excessive time on multiple rebuilds when the RF modules were likely defective. If I could advise my past self, I would tell myself that when trying something new, always start with a reliable base and get the small things working before moving on to more complex tasks. This tip would've saved me a lot more time troubleshooting and figuring out how to fix something complex. Ultimately, I learned to also recognize when to stop when something goes the way you didn't expect and to have a backup plan to fall on.
If I were to build another iteration of the project, I would get new RF models and start doing some basic code to test them, and then start implementing the rest of my project's components.
/*
Washer Dryer Timer for 60-223 Intro to Physical Computing
Code written by Copilot.
This is a Transmitter sketch that monitors movement using a 3-axis analog accelerometer. When the start button is pressed, it calibrates the current XYZ axis readings of the accelerometer. When any value changes with movement, send a signal LCD display to the receiver Arduino. When 1 second of stillness in all 3 axes is detected, send another LCD display signal to the receiver Arduino. When
the reset button is pressed, it sends a signal to reset the cycle to the receiver Arduino.
pin mapping:
Arduino pin | role | description
-------------------------------------
A0 input X-Axis Accelerometer
A1 input Y-Axis Accelerometer
A2 input Z-Axis Accelerometer
5 intput Reset Cycle Button
4 intput Start Cycle Button
Tx output Serial Transmission
*/
//Pin Configuration
const int xPin = A0;
const int yPin = A1;
const int zPin = A2;
const int startButtonPin = 4;
const int resetButtonPin = 5;
//Calibration + Detection Variables
int xRest = 0;
int yRest = 0;
const int tolerance = 12; // Tolerance of movement
const unsigned long stillDuration = 1000; // Require 1 seconds of stillness to stop
//State Flags
bool monitoring = false;
bool hasStarted = false;
bool hasStopped = false;
bool vibrationEnabled = false;
//Timing
unsigned long stillStartTime = 0;
//Function to Smooth Readings
int smoothRead(int pin) {
long sum = 0;
const int samples = 10; // average 10 samples
for (int i = 0; i < samples; i++) {
sum += analogRead(pin);
delay(2);
}
return sum / samples;
}
void setup() {
Serial.begin(9600);
pinMode(startButtonPin, INPUT_PULLUP);
pinMode(resetButtonPin, INPUT_PULLUP);
//Calibrate Accelerometer at Rest
Serial.println("Calibrating accelerometer...");
delay(1000);
long xSum = 0, ySum = 0;
const int samples = 100;
for (int i = 0; i < samples; i++) {
xSum += analogRead(xPin);
ySum += analogRead(yPin);
delay(10);
}
xRest = xSum / samples;
yRest = ySum / samples;
Serial.print("Calibration complete.\nRest X: ");
Serial.print(xRest);
Serial.print(" | Rest Y: ");
Serial.println(yRest);
Serial.println("System ready.\n");
}
//Manual Start Button
void loop() {
if (digitalRead(startButtonPin) == LOW && !monitoring) {
delay(50);
if (digitalRead(startButtonPin) == LOW) {
Serial.println("CMD:S"); // replaced Serial.write('S');
monitoring = true;
vibrationEnabled = true;
hasStarted = false;
hasStopped = false;
stillStartTime = 0;
Serial.println("Monitoring started.");
}
}
//Manual Reset Button
if (digitalRead(resetButtonPin) == LOW) {
delay(50);
if (digitalRead(resetButtonPin) == LOW) {
Serial.println("CMD:R"); // replaced Serial.write('R');
monitoring = false;
vibrationEnabled = false;
hasStarted = false;
hasStopped = false;
stillStartTime = 0;
Serial.println("System reset.");
}
}
if (!vibrationEnabled || hasStopped) return;
//Read Smoothed Accelerometer Values
int x = smoothRead(xPin);
int y = smoothRead(yPin);
int z = smoothRead(zPin);
bool xStill = abs(x - xRest) <= tolerance;
bool yStill = abs(y - yRest) <= tolerance;
bool moving = !(xStill && yStill);
//Debug Output
Serial.print("X: "); Serial.print(x);
Serial.print(" | Y: "); Serial.print(y);
Serial.print(" | Status: ");
Serial.println(moving ? "Moving" : "Still");
//Start Signal on Movement
if (!hasStarted && moving) {
Serial.println("CMD:1");
hasStarted = true;
Serial.println("Cycle started (movement detected).");
}
//Stop Signal after Sustained Stillness
if (hasStarted && !hasStopped) {
if (!moving) {
//Right as stillness is detected, start the stillness timer
if (stillStartTime == 0) {
stillStartTime = millis();
Serial.println("Stillness timer started...");
}
//If still for at least stillDuration, stop the cycle
if (millis() - stillStartTime >= stillDuration) {
Serial.println("CMD:0"); // replaced Serial.write('0');
hasStopped = true;
Serial.println("Cycle complete (still for 4s).");
}
} else {
// Reset timer if movement resumes
stillStartTime = 0;
}
}
delay(100);
}
/*
Washer Dryer Timer for 60-223 Intro to Physical Computing
Code written by Copilot.
This is a Receiver sketch that reads signals and display visuals on the LCD display. When power is pluged in display "Press to
Start Cycle". When read the signal of the start cycle button being pressed display "Ready to Start Awaiting Move". When
it reads the signal of movement detected display a count up timer and "Cycle Running". When signal of stillness is read display
a flashing "Cycle Complete" with the total time of the cycle. When signal of reset cycle button is read clear LCD screen and go
back to the "Press to Start Cycle".
pin mapping:
Arduino pin | role | description
-------------------------------------
Rx input Serial Reception
Vin(pin) input Power Coming from Transmitter Arduino
SDA output LCD display
SCL output LCD display
*/
#include <Wire.h> // I2C communication for LCD
#include <LiquidCrystal_I2C.h> // LCD display over I2C
LiquidCrystal_I2C lcd(0x27, 16, 2); // Set up LCD at I2C address 0x27
void setup() {
lcd.init(); // Initialize LCD
lcd.backlight(); // Turn on LCD backlight
lcd.clear(); // Clear LCD display
lcd.setCursor(0, 0); // Set LCD cursor
lcd.print("Press to"); // Display message on LCD
lcd.setCursor(0, 1);
lcd.print("Start Cycle");
Serial.begin(9600); // Start serial communication
}
void loop() {
while (Serial.available()) {
char c = Serial.read(); // Read serial input
if (c == '\n') {
processCommand(inputString);
inputString = "";
} else {
inputString += c;
}
}
if (running) {
unsigned long elapsed = millis() - startTime;
lcd.setCursor(0, 1); // Update LCD with elapsed time
displayTime(elapsed);
}
if (completed && !running) {
if (millis() - lastBlinkTime >= blinkInterval) {
blinkState = !blinkState;
lcd.setCursor(0, 0); // Blink "Cycle Complete" on LCD
lcd.print(blinkState ? "Cycle Complete " : " ");
lastBlinkTime = millis();
}
}
}
void processCommand(String cmd) {
cmd.trim();
if (cmd == "CMD:S") {
lcd.clear(); // Clear LCD
lcd.setCursor(0, 0);
lcd.print("Ready to Start"); // Show ready message
lcd.setCursor(0, 1);
lcd.print("Awaiting Move");
Serial.println("LCD: Ready to Start"); // Send status over Serial
}
else if (cmd == "CMD:1" && !running && !completed) {
startTime = millis();
lcd.clear(); // Clear LCD
lcd.setCursor(0, 0);
lcd.print("Cycle Running"); // Show running message
Serial.println("LCD: Running");
}
else if (cmd == "CMD:0" && running) {
finalTime = millis() - startTime;
lcd.clear(); // Clear LCD
lcd.setCursor(0, 0);
lcd.print("Cycle Complete"); // Show complete message
lcd.setCursor(0, 1);
displayTime(finalTime); // Show final time
lastBlinkTime = millis();
Serial.println("LCD: Complete");
}
else if (cmd == "CMD:R") {
lcd.clear(); // Clear LCD
lcd.setCursor(0, 0);
lcd.print("Press to"); // Reset to initial message
lcd.setCursor(0, 1);
lcd.print("Start Cycle");
Serial.println("LCD: Reset");
}
}
void displayTime(unsigned long timeMs) {
int seconds = (timeMs / 1000) % 60;
int minutes = (timeMs / 60000) % 60;
int hours = (timeMs / 3600000);
lcd.print("Time "); // Print time to LCD
if (hours < 10) lcd.print('0');
lcd.print(hours); lcd.print(':');
if (minutes < 10) lcd.print('0');
lcd.print(minutes); lcd.print(':');
if (seconds < 10) lcd.print('0');
lcd.print(seconds);
}