Reach for the stars
REACH FOR THE STARS
"Reach for the Stars" is a visualized focus timer that enables user to focus on their tasks by displaying four different constellations based on the time phase. My personal interest in constellations enables me to be motivated with my own goals whenever I see them, therefore is a very personal tool for me to focus on my academic assignments.
Process Images
The design process for this project began with the creation of an initial prototype using cardboard as the primary material. This served as a tangible starting point, allowing me to visualize and refine the concept. Moving forward, I transitioned from the cardboard prototype to the actual final project fabrication. Using laser cutting, various components were meticulously crafted throughout numerous attempts, as you can see in the second photo with specific elements marked in red to indicate areas requiring dimension adjustments. With the physical structures taking shape, I turned my attention to the crucial functionality of the project. All other components that I have included such as slide potentiometers and rotary encoders did not specifically need extra layers of precision, therefore was an easy process to fabricate and install. However, as the NeoPixel libraries came into play, the functionalities of NeoPixel LEDs took a laborious and long process to execute. The first attempt served as a baseline, and I was satisfied to observe that all the LEDs were functioning as expected, however the wires were fragile enough to break in middle of the critique day. Thus, I decided to rewire the NeoPixel LEDs in a different configuration and resources for a second test run. This adjustment allowed me to fine-tune the lighting effects and explore alternative design possibilities. By iterating and refining our project through these meticulous steps, I was able to transform an initial idea into a well-crafted and functional work of art, embodying both creativity and precision.
Discussion
One of the responses I received from the critique itself was that the idea was very creative and it was disappointing to see the execution not possible in the actual critique (I agree very much). Another comment I received is that they could see my passion in the overall project. This was really appreciating because I hoped that the audience could at least see my effort in the overall failed attempt at the execution. However, regardless of these great comments from my peers, I don’t really quite appreciate the way my project was made. I do not appreciate how dirty the wiring is, or the material I've used to achieve this kind of look. Although the idea in my head was a very ambitious one, the more and more I worked on the fabrication itself, the project took a turn in a way that I did not anticipate. There are a lot more aspects that I don’t appreciate about it, and I would take this opportunity to say that I have a lot more to learn about in the upcoming weeks. Through this project, I painfully learned that fabrication is not so easy. Although I’ve always had a very high confidence in terms of creating things aesthetically as an art student, I have come to realize that fabrication in terms of ‘design technology’ is a different field that I should study more about. I spent a significant amount of time soldering the wires instead of coding, which was a big surprise on my end because I have so much less confidence AND experience in coding. Overall this project itself was just a huge learning experience; I’ve learned about what I’m incapable / capable of, and learned so much more about the tools that I have overseen in the past. I would not build another iteration of this project just because I want to move on from the fight I’ve battled with this project, but if I had to, I would definitely plan more considerately on each aspects on the project rather than jumping straight into the fabrication and wasting time pondering about what it ‘could have been’.
Technical Information (Block diagram + Schematic diagram)
Code Submission
// The provided Arduino code orchestrates an interactive system involving a button, a rotary encoder, a slide potentiometer, // NeoPixel LEDs, and a LiquidCrystal display. It allows users to set and activate a timer through button presses, adjusting // time with the rotary encoder, and displays time remaining on the LCD. The code features four distinct constellation patterns // displayed via NeoPixel LEDs, done by boolean arrays to control individualized NeoPixels. Additionally, the colors of the LEDs // can be controlled by the slide potentiometer's analog input. When the timer reaches zero, a default pattern illuminates the // final constellation while a concluding message appears on the LCD, creating an engaging visual experience tied to the timer // functionality.
// Pin mapping:
// NeoPixel Chain PIN: 13
// SW in Rotary Encoder: 3
// DT in Rotary Encoder: 4
// Click Pin in Rotary Encoder: 5
// Slide Potentiometer: A0
#include <BfButton.h>
#include <Adafruit_NeoPixel.h>
#include <LiquidCrystal_I2C.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 13
#define NUMPIXELS 12
#define btnPin 3
#define DT 4
#define CLK 5
#define slide A0
int seconds = millis()*1000;
BfButton btn(BfButton::STANDALONE_DIGITAL, btnPin, true, LOW);
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
LiquidCrystal_I2C lcd(0x27,16,2);
// Arrays for different constellation on NeoPixel LEDs
bool libraArray[11] = {1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0};
bool cancerArray[11] = {1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0};
bool dipperArray[11] = {0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1};
bool ariesArray[11] = {0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0};
bool defaultArray[11] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int counter = 0;
int setTimer = 0;
int angle = 0;
int aState;
int aLastState;
bool systemOn = false;
bool inTimer = false;
int elapsedTime = 0;
int startTime=0;
bool start=0;
//Button press hanlding function for single press, double press, and long press
void pressHandler (BfButton *btn, BfButton::press_pattern_t pattern) {
switch (pattern) {
case BfButton::SINGLE_PRESS:
Serial.println("Single push");
setTimer = counter;
inTimer = !inTimer;
break;
case BfButton::DOUBLE_PRESS:
Serial.println("Double push");
inTimer = false;
counter = 0;
start = 0;
break;
case BfButton::LONG_PRESS:
Serial.println("SystemOn!");
systemOn = !systemOn;
if (systemOn == true){
lcd.println("Timer is on!");
}
else{
lcd.println("Timer is off :(");
}
Serial.println(systemOn);
break;
}
}
void setup() {
lcd.init();
lcd.clear();
lcd.backlight();
pixels.begin();
Serial.begin(9600);
Serial.println(angle);
pinMode(CLK,INPUT_PULLUP);
pinMode(DT,INPUT_PULLUP);
pinMode(slide, INPUT);
aLastState = digitalRead(CLK);
btn.onPress(pressHandler)
.onDoublePress(pressHandler)
.onPressFor(pressHandler, 1000);
}
void loop() {
btn.read();
// rotary encoder reading part
if (systemOn && inTimer==false){
aState = digitalRead(CLK);
if (aState != aLastState){
if (digitalRead(DT) != aState) {
counter ++;
angle ++;
}
else {
counter--;
angle --;
}
if (counter >=120 ) {
counter = 120;
}
if (counter <=0 ) {
counter = 0;
}
lcd.clear();
lcd.print(counter);
}
aLastState = aState;
pixels.setBrightness(60);
}
else{
pixels.setBrightness(30);
}
// set the timer if its presse
if (setTimer > 0 && inTimer == true){
int timerDuration = setTimer * 60; // in seconds
if(start==0){
startTime= starttimer();
start=1;
}
unsigned long mil = millis() / 1000;
int remainingTime = timerDuration - mil;
drawsign(timerDuration, remainingTime);
int LCDPrintRemainingTime = remainingTime / 60;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Remaining Time:");
lcd.setCursor(0,1);
lcd.println(LCDPrintRemainingTime);
if (remainingTime == 0){
inTimer = false;
setTimer = 0;
counter = 0;
timerDuration = 0;
remainingTime = 0;
elapsedTime = 0;
ending();
}
}
}
// ------------------------------------------------------------------------------------------------------------------------ constellation functions
int starttimer(){
startTime=millis();
}
void drawsign(int timerDuration, int elapsedTime){
if ((timerDuration * (3/4)) <= elapsedTime){
pixels.clear();
libra();
}
else if ((timerDuration * (3/4)) >= elapsedTime && (timerDuration * (1/2)) < elapsedTime ){
pixels.clear();
dipper();
}
else if ((timerDuration * (1/2)) > elapsedTime && (timerDuration * (1/4)) < elapsedTime){
pixels.clear();
aries();
}
else if ((timerDuration * (1/4)) > elapsedTime){
pixels.clear();
cancer();
}
}
void libra(){
int potVal = 0;
potVal = analogRead(slide);
int colorVal = map(potVal, 0, 1023, 0, 255);
pixels.clear();
for (int i = 0; i < NUMPIXELS; i++){
pixels.setBrightness(100);
if (libraArray[i]){
pixels.setPixelColor(i, pixels.Color(colorVal, 150, 255));
pixels.show();
}
}
}
void aries(){
pixels.clear();
int potVal = 0;
potVal = analogRead(slide);
int colorVal = map(potVal, 0, 1023, 0, 255);
for (int i = 0; i < NUMPIXELS; i++){
pixels.setBrightness(100);
if (ariesArray[i]){
pixels.setPixelColor(i, pixels.Color(colorVal, 150, 255));
pixels.show();
}
}
}
void cancer(){
int potVal = 0;
potVal = analogRead(slide);
int colorVal = map(potVal, 0, 1023, 0, 255);
pixels.clear();
for (int i = 0; i < NUMPIXELS; i++){
pixels.setBrightness(100);
if (cancerArray[i]){
pixels.setPixelColor(i, pixels.Color(colorVal, 150, 255));
pixels.show();
}
}
}
void dipper(){
int potVal = 0;
potVal = analogRead(slide);
int colorVal = map(potVal, 0, 1023, 0, 255);
pixels.clear();
for (int i = 0; i < NUMPIXELS; i++){
pixels.setBrightness(100);
if (dipperArray[i]){
pixels.setPixelColor(i, pixels.Color(colorVal, 150, 255));
pixels.show();
}
}
}
void ending(){
for (int i = 0; i < NUMPIXELS; i++){
pixels.setBrightness(100);
if (defaultArray[i]){
pixels.setPixelColor(i, pixels.Color(255, 0, 0));
pixels.show();
}
}
lcd.print("Reach for the stars");
}