Overview
Above is the front view of the nightlight. It is at the pre-sleep mode, the figure shows "G-Night". It shows a soft green glow.
A brief explanation of the project.
This project is an emotional support nightlight to relieve my pre-sleep anxiety. With two modes, it softly reminds me of when to go to bed without causing anxiety (because that's my own original character why would I be scared of him). Except for that, it also has two faces of my origincal character on it. When turned on, it is at the pre-sleep mode, which shows a happy face of my character and of the light color that I can adjust. When one hour passed by, it turns into the angry mode, where a not-so-happy face of the character is shown and the light color turns to the opposite on the hue ring. After the other 1 hour, it will automatically shut down and turn on again at the same time tomorrow. The hue and the brightness are both adjustable.
At least four good still images of the final project.
A perspective view of the nightlight. It's a glowy box with soft green glow. Shows two potentiometers which has brightness and hues tag on it. The two figures of the character engraved on acrylic is shown in the middle of the box.
The inner loop of the nightlight. An arduino board and two bread boards and a servo motor peeped from the acrylic lid. There is also a huge metal round item which is the heat dismiss device of the LED light. Also three chip-like LED drivers.
A closeup of the figure engraved on an acrylic piece at the middle of the nightlight. The caption said "G-Night" and is lit up in soft green glow.
Another closeup of the figure engraved on an acrylic piece at the middle of the nightlight. The caption said "G-Night" and is lit up in soft teal glow. It's taken from the side view so the light condition is a little different from the other picture. In this one, the outline of the character is lit up by the teal, makes it lighter than the other spaces.
Moving image
In this video, the nightlight shows three different stages. At first it is on, and I also adjusted the brightness and hues to show the capability of it. Then it turns into the angry mode, with the light changing from green to purple, and the facial expression of the character also changes when the servo motor works. Then after the other 1 min, it automatically shut down and returns to a default stage.
Process images and review
The electronic part of the project. The LED is wired on three drivers, the potentiometer also showned. And a servo motor. This is the part that used the most effort since it requires 24 points to solder.
At first I tried to engrave the character using a pixel-vector transformer. I hand drew the character and then transformed it into SVG. However, it doesn't work on the laser cutter and the engrave looks like dots.
I was told that the laser cutter cannot cut short lines and has to cut in loops, so I mouse drew the character again in Rhino, a 3d software, this time uses loops instead of lines. This is a screenshot of my work in Rhino.
The final result turns out to be fine and usable for the project. These are two close-up to the engraved acrylic pieces.
Because the final outcome of the servo motor-character part is not capable with the original lid design, I hand cut another lid with wooden sticks and transparent plastic box. It magically works.
It's really interesting as I didn't expect the engraving does take much more time than what I have expected. I thought the most difficult part would be the electronics and thus saved less time than I thought for fabrication and more on the electronics.
However, the actual fabrication process had up to at least 2/3 of it contributes to the time it took to engrave the character that I have already drawn!
The outcome is also welcoming though, since the engraved acrylic character did receive a lot of attention.
Discussion
Responses to my project is pretty positive as compared to my expectation. I thought people would be mad at the plastic box lid on the nightlight, but instead, what they seem to be more focus on is the size of the box. “I’m wondering if it’s possible to scale the box down.” Yutong Wrote. "Right now, the box seems a bit bulky, and I’m not sure how it’ll be placed near your bed. " Estee also wrote. There has to be some ways to shrink the size of the box down and have the character larger. For example, I can take the servo motor out of the box and mount it to a stick instead of a panel. Besides this, the fact the I used two bread boards could also contributes to the size of the box. Electronic engineering vise it's much easier to have more space for a high-power LED which has a large heat dismiss part and has to be soldered to three drivers itself. However, if to consider from a perspective of a designer, I shall not pass the size of this product considering its desired function of company. Besides this, they like the engraved character because it is cute and full of personalized emotional experience. "I really love the incorporation of your character, I think it adds a cool story for your piece", wrote Zar. I mean, that is also my favorite part. That is the reason why I made the project. This is the best merchandise of my original character, with a series of literally neon-rainbow-lighted functions and movable parts. As a result, I expect people to like this part and to want one for their loved fictional characters.
From my own perspective, I love how the outcome comes out. It's a lot scrappier than what I have imagined, but the fact of it working is so satisfying. I would definitely add more function if I were left to improve it. In the dark, all of your senses are highly improved, not only the visual aspect. It's reasonable for this nightlight to have something else than the visual effect. For example, in the original plan I planned to add an DF Mini-player to play light music and switch to another piece of music when it turns into the angry mode. Also, I even consider to voice over my character to play a piece of line or so to remind me of putting my phone down and going to sleep. I also planned a similar product as a projector, and if I have a chance, I will also dive deeper into that aspect too. I also would like it in my bedroom, but before that, I want to combine the three power supplies into one. Because for now, the fact that it needs three power supplies make it almost impossible to use from day to day.
When I was making the project, I was also in one of the worst days in the semester with a lot of unrelated personal negative events going on. As a result, I had to treat the project as an escape instead of as a project, because that's the only time that I don't need to think about other terrible things. This put me into another work status else than what I am used to. Also because how emotionally heavy this project is, there's almost a faith of me to push the project to the limit where I want it to be at. The nature of the project also created a lot of incertainties, since the servo motor and the jacks of the power supplies don't have given measurements from factories. I have to measure them and find out that they are the other size. This and the difficulties of engraving made the fabrication part extremely difficult. I have to adapt to the changes. I sanded the acrylic panel which I planned to mount the servo motor and couldn't because of the size difference. Those are really moments that I have never expected when project 2 is introduced.
For next steps, I think what I included in my own reflection would be enough to start with. But, yes, I will start with decreasing the number of the power supplies. I think adding a buck convertor would be the first step I want to do. Also, I want to re-lasercut the lid again to replace the plastic lid.
Technical information
Code submission, embedded into the project page
/*
Original Character Nightlight for 60-223 F25 project 2
Reads RTC and two potentiometers as input and drives a high power RGB LED and a servo motor as output. A nightlight includes 3 stages that enables hue and brightness adjustments.
P.S. This is an exhibition code for showing the loop in a favor of 3 min. Not in 24 hours.
Some sources that I used:
Course official website
Hue to rgb code original Javascript edition: https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
RTC resources: https://projecthub.arduino.cc/ejshea/real-time-clock-d01fa3
ChatGPT helps me: translating the Javascript code to C regarding the hsl to rgb transformation.
Claude helps me: a more pleasing form in serial monitor to check on time and status.
hue shifts 180 degree on the ring code.
pin mapping:
Arduino pin | role | description
___________________________________________________________________
A1 input potentiometer for adjusting brightness
A2 input potentiometer for adjusting hue
A4 input SDA
A5 input SCL
3 output LED Red driver
5 output LED Green driver
6 output LED Blue driver
9 output Servo Motor
by Hua Tong, htong2@andrew.cmu.edi
*/
//library for servo motor
#include <Servo.h>
//library for RTC
#include <Wire.h>
#include "RTClib.h"
//library for math functions
#include <math.h>
// pin definition
const int SERVO_PIN = 9;
const int POT_BRIGHT_PIN = A1;
const int POT_HUE_PIN = A2;
const int LED_R_PIN = 3;
const int LED_G_PIN = 5;
const int LED_B_PIN = 6;
// 3 min loop for pre-sleep, angry and auto rest
const unsigned long CYCLE_DURATION = 180000;
const unsigned long LED_ON_DURATION = 60000;
const unsigned long ANGRY_DURATION = 60000;
const unsigned long REST_DURATION = 60000;
//import parts
RTC_DS1307 rtc;
Servo servoMotor;
//set default variables
unsigned long cycleStartTime = 0;
int baseHue = 0;
int brightness = 255;
bool angryMode = false;
int hueOffset = 0;
// HSL to RGB function
void hslToRgb(float h, uint8_t lightness255, uint8_t &r, uint8_t &g, uint8_t &b) {
float H = fmod(h, 360.0f);
float L = constrain(lightness255 / 255.0f, 0.0f, 1.0f);
float S = 1.0f;
float C = (1.0f - fabs(2.0f * L - 1.0f)) * S;
float Hprime = H / 60.0f;
float X = C * (1.0f - fabs(fmod(Hprime, 2.0f) - 1.0f));
float r1 = 0.0f, g1 = 0.0f, b1 = 0.0f;
if (Hprime >= 0 && Hprime < 1) { r1 = C; g1 = X; b1 = 0; }
else if (Hprime < 2) { r1 = X; g1 = C; b1 = 0; }
else if (Hprime < 3) { r1 = 0; g1 = C; b1 = X; }
else if (Hprime < 4) { r1 = 0; g1 = X; b1 = C; }
else if (Hprime < 5) { r1 = X; g1 = 0; b1 = C; }
else { r1 = C; g1 = 0; b1 = X; }
float m = L - C / 2.0f;
float rf = r1 + m;
float gf = g1 + m;
float bf = b1 + m;
r = (uint8_t)round(constrain(rf, 0.0f, 1.0f) * 255.0f);
g = (uint8_t)round(constrain(gf, 0.0f, 1.0f) * 255.0f);
b = (uint8_t)round(constrain(bf, 0.0f, 1.0f) * 255.0f);
}
// setup
void setup() {
Serial.begin(9600);
Wire.begin();
rtc.begin();
// servo motor setup
servoMotor.attach(SERVO_PIN);
delay(100);
servoMotor.write(30); // original position to 30 degrees
delay(500);
pinMode(LED_R_PIN, OUTPUT);
pinMode(LED_G_PIN, OUTPUT);
pinMode(LED_B_PIN, OUTPUT);
cycleStartTime = millis();
Serial.println("System started - 3-minute cycle: LED_ON(1min) -> ANGRY(1min) -> REST(1min)");
}
// loop starts
void loop() {
// decide time in the loop
unsigned long currentTime = millis();
unsigned long elapsedTime = currentTime - cycleStartTime;
// reset loop if over 3 min
if (elapsedTime >= CYCLE_DURATION) {
cycleStartTime = currentTime;
elapsedTime = 0;
Serial.println("\n=== NEW CYCLE STARTING ===\n");
}
// analogRead potentiometers
int potHueVal = analogRead(POT_HUE_PIN);
int potBrightVal = analogRead(POT_BRIGHT_PIN);
baseHue = map(potHueVal, 0, 1023, 0, 360);
brightness = map(potBrightVal, 0, 1023, 0, 255);
bool ledOn = false;
int finalHue = baseHue;
static int currentServoAngle = 0;
if (elapsedTime < LED_ON_DURATION) {
// Pre-sleep mode
ledOn = true;
angryMode = false;
hueOffset = 0;
finalHue = baseHue;
static bool servoSet = false;
if (!servoSet) {
Serial.println("Setting servo to 15 degrees...");
servoMotor.write(30);
currentServoAngle = 30;
servoSet = true;
}
} else if (elapsedTime < LED_ON_DURATION + ANGRY_DURATION) {
// Angry mode
ledOn = true;
angryMode = true;
hueOffset = 180;
finalHue = (int)(baseHue + hueOffset) % 360;
static bool servoMoved = false;
if (!servoMoved) {
currentServoAngle = currentServoAngle + 90;
Serial.print("Rotating servo +90 degrees to ");
Serial.print(currentServoAngle);
Serial.println(" degrees...");
servoMotor.write(currentServoAngle);
servoMoved = true;
}
} else {
// Rest mode
ledOn = false;
angryMode = false;
hueOffset = 0;
static bool servoReturned = false;
if (!servoReturned) {
Serial.println("Returning servo to 15 degrees...");
servoMotor.write(30);
currentServoAngle = 30;
servoReturned = true;
}
}
uint8_t r, g, b;
hslToRgb(finalHue, brightness, r, g, b);
if (ledOn) {
analogWrite(LED_R_PIN, r);
analogWrite(LED_G_PIN, g);
analogWrite(LED_B_PIN, b);
} else {
analogWrite(LED_R_PIN, 0);
analogWrite(LED_G_PIN, 0);
analogWrite(LED_B_PIN, 0);
}
// Serial Monitor Ouput
DateTime now = rtc.now();
Serial.print("RTC: ");
if (now.hour() < 10) Serial.print('0');
Serial.print(now.hour());
Serial.print(":");
if (now.minute() < 10) Serial.print('0');
Serial.print(now.minute());
Serial.print(":");
if (now.second() < 10) Serial.print('0');
Serial.print(now.second());
Serial.print(" | Cycle: ");
Serial.print(elapsedTime / 1000);
Serial.print("s / 180s");
Serial.print(" | Base Hue: ");
Serial.print(baseHue);
Serial.print(" Final Hue: ");
Serial.print(finalHue);
Serial.print(" Brightness: ");
Serial.print(brightness);
Serial.print(" | LED: ");
Serial.print(ledOn ? "ON" : "OFF");
Serial.print(" Angry: ");
Serial.println(angryMode ? "YES" : "NO");
delay(1000);
}