Johan Sandoval
Published

Lane Tech HS - PCL - Moon Phases Visualization

Pulls the current moon phase every hour and updates a motor that projects a silhouette to represent the shadow casted on the moon.

BeginnerFull instructions provided3 hours254
Lane Tech HS - PCL - Moon Phases Visualization

Things used in this project

Hardware components

Argon
Particle Argon
×1
5V DC Stepper Motor with ULN2003 Driver Board
×1
Jumper wires (generic)
Jumper wires (generic)
×6
6 Inch Wooden Stick
×1
Circular Disk
×1
Light
×1
Funnel
×1
Rubber Bands
×1
Velcro
×1

Software apps and online services

Visual Crossing Weather API
Particle Build Web IDE
Particle Build Web IDE
Tera Term Serial Monitor

Hand tools and fabrication machines

Drill / Driver, Cordless
Drill / Driver, Cordless
Multitool, Screwdriver
Multitool, Screwdriver

Story

Read more

Schematics

Stepper Motor

Stepper Motor Schematic

Stepper Motor File

Code

Source Code

C/C++
This code pulls data from a webhook event that accesses an API that returns the fractional portion through the current moon lunation cycle that is then turned into a number of steps that a motor then performs to represent the current moon phase.
//Define variables for the pins on motor, the timer, and the old moon phase.
#define STEPPER_PIN_1 5
#define STEPPER_PIN_2 6
#define STEPPER_PIN_3 7
#define STEPPER_PIN_4 8
int step_number = 0;
int timer = 0;
float oldPhase = 0.00;


void setup() 
{
    //Initialize motor pins
    pinMode(STEPPER_PIN_1, OUTPUT);
    pinMode(STEPPER_PIN_2, OUTPUT);
    pinMode(STEPPER_PIN_3, OUTPUT);
    pinMode(STEPPER_PIN_4, OUTPUT);
    
    // Subscribe to the webhook response event.
    Particle.subscribe("hook-response/moonPhase", myHandler, MY_DEVICES);
    Serial.begin(9600);
    //Initializes current moon phase by calling webhook event.
    Particle.publish("moonPhase");
}

void loop()
{
  //A timer that updates every second and if the timer reaches 3600 seconds or 1 hour, the webhook event is published.
  delay(1000);
  timer++;
  if(timer == 3600){
    Particle.publish("moonPhase");
    timer = 0;
  }
}

void myHandler(const char *event, const char *data) 
{
    //When the webhook response is published, data is pulled Visual Crossing API that contains a float value from 0.00 - 1.00 that represents the fractional portion through the current moon lunation cycle.
    String phaseName = "";
    float moonphase = atof(data);
    if(moonphase == 0)
    {
        phaseName = "New Moon";
    }
    else if(moonphase < 0.25)
    {
        phaseName = "Waxing Crescent";
    }
    else if(moonphase == 0.25)
    {
        phaseName = "First Quarter";
    }
    else if(moonphase < 0.5)
    {
        phaseName = "Waxing Gibbous";
    }
    else if(moonphase == 0.5)
    {
        phaseName = "Full Moon";
    }
    else if(moonphase < 0.75)
    {
        phaseName = "Waning Gibbous";
    }
    else if(moonphase == 0.75)
    {
        phaseName = "Last Quarter";
    }
    else if(moonphase <= 1)
    {
        phaseName = "Waning Crescent";
    }
    Serial.print("Current Moon Phase: " + phaseName + " ");
    Serial.println(moonphase);
    
    //Every time the webhook is called, the data is stored in a variable called moon phase which is then translated to the number of steps needed to get to that current moon phase. The calculation takes the old moon phase, the phase the moon was last hour (which will always be 0.00 or a New Moon on first startup), and subtract it from the current moon phase. This subtraction will give you a number between 0.00 - 1.00 due to the moon phase always incrementing positively before resetting back to 0.00 in which case the old phase is incremented back to 0.00 as well. This number can then be multiplied by 1000 where it will represent the number of steps needed to create the current moon phase.
    int steps = (moonphase - oldPhase) * 1000;
    
    //These steps are used to move the motor X number of steps counterclockwise of neutral position which will always be 0.00 or a New Moon. If X number of steps is greater than 500 the motor will start from the left side to represent the full moon cycle.
    if(moonphase >= 0.00 && moonphase < 0.50){
        for(int a=0; a<steps; a++){
            OneStep(false);
            delay(2);
        }
    }
    
    if(moonphase == 0.50 && oldPhase != 0.50){
      for(int a=0; a<1000; a++){
            OneStep(true);
            delay(2);
        }  
    }
    
    if(moonphase > 0.50 && moonphase <= 1.1){
        for(int a=0; a<steps; a++){
            OneStep(false);
            delay(2);
        }
    }
    
    //After all, calculations are done, the old moon phase is then set to the current moon phase to be ready to be used for the next calculation that will be down the following hour.
    oldPhase = moonphase;
    
    if(moonphase >= 1.00){
        oldPhase = 0.00;
    }
    
}

void OneStep(bool dir){
    //Takes a boolean to determine whether the motor should move a step clockwise (true) or counterclockwise (false). This function is the sequence of one step and can be used in a loop to move X amount of steps in either direction.
    if(dir){
        switch(step_number){
            case 0:
                digitalWrite(STEPPER_PIN_1, HIGH);
                digitalWrite(STEPPER_PIN_2, LOW);
                digitalWrite(STEPPER_PIN_3, LOW);
                digitalWrite(STEPPER_PIN_4, LOW);
                break;
            case 1:
                digitalWrite(STEPPER_PIN_1, LOW);
                digitalWrite(STEPPER_PIN_2, HIGH);
                digitalWrite(STEPPER_PIN_3, LOW);
                digitalWrite(STEPPER_PIN_4, LOW);
                break;
            case 2:
                digitalWrite(STEPPER_PIN_1, LOW);
                digitalWrite(STEPPER_PIN_2, LOW);
                digitalWrite(STEPPER_PIN_3, HIGH);
                digitalWrite(STEPPER_PIN_4, LOW);
                break;
            case 3:
                digitalWrite(STEPPER_PIN_1, LOW);
                digitalWrite(STEPPER_PIN_2, LOW);
                digitalWrite(STEPPER_PIN_3, LOW);
                digitalWrite(STEPPER_PIN_4, HIGH);
                break;
        } 
    }
    
    else{
        switch(step_number){
            case 0:
                digitalWrite(STEPPER_PIN_1, LOW);
                digitalWrite(STEPPER_PIN_2, LOW);
                digitalWrite(STEPPER_PIN_3, LOW);
                digitalWrite(STEPPER_PIN_4, HIGH);
                break;
            case 1:
                digitalWrite(STEPPER_PIN_1, LOW);
                digitalWrite(STEPPER_PIN_2, LOW);
                digitalWrite(STEPPER_PIN_3, HIGH);
                digitalWrite(STEPPER_PIN_4, LOW);
                break;
            case 2:
                digitalWrite(STEPPER_PIN_1, LOW);
                digitalWrite(STEPPER_PIN_2, HIGH);
                digitalWrite(STEPPER_PIN_3, LOW);
                digitalWrite(STEPPER_PIN_4, LOW);
                break;
            case 3:
                digitalWrite(STEPPER_PIN_1, HIGH);
                digitalWrite(STEPPER_PIN_2, LOW);
                digitalWrite(STEPPER_PIN_3, LOW);
                digitalWrite(STEPPER_PIN_4, LOW);
                break;
  
            }
    } 
    
    step_number++;
    
    if(step_number > 3){
        step_number = 0;
    }
}

Credits

Johan Sandoval

Johan Sandoval

3 projects • 4 followers

Comments

Add projectSign up / Login