PHYS S-12 : Dan's Documentation

Machine Building

Day 10: 7/23

I wanted to automate my curtains for this assignment. I want my curtains to open at set times in the morning and let the sunlight wake me up naturally.

Plan

The plan is very simple, my curtain has two strings which opens/closes it. I'll attach a motor to each one, spinning in opposite directions. This will let me pull on one string while letting go of the other.

Stepper Motors

Stepper motors are perfect for this application since it will repeatedly turn the same amount of rotations. I hooked up two motors to my metro, following my own documentation. I used a 9v power supply.

Then I uploaded the sample code with slight modifications to accommodate two motors, and they ran as expected.

Attaching to the Curtain

Next, I wrapped a string around the motor shaft and tied the string's other end to my curtain.

string_motor
String Attached to Motor
string_curtain
String Attached to Curtain

With the strings attached, I tested the directions of the motors and found that positive for motor one and negative for motor two worked well.

Installation

I needed to install the motors below the curtain in a permanent way. I did this by turning a card game box into a case, which I then hot glued to the ground. The case for my motors had two holes in the back to allow for wires to pass through, and it also had two openings at the top for the strings. I also hot glued the motors to the casing to ensure that they wouldn't move around.

box
Case for Motors
setup
Machine Set Up

Code

The code I used is very similar to the one provided to us during class. Here it is:


#include <Stepper.h>

const int stepsPerRevolution = 200;  //200 for our steppers.

// initialize the stepper library for two steppers:
Stepper Stepper1(stepsPerRevolution, 11, 10, 9, 8);
Stepper Stepper2(stepsPerRevolution, 7, 6, 5, 4);

void setup() {
    Serial.begin(9600);              //This is the USB serial.
    Serial.setTimeout(20);        //Set wait time for serial data to 20ms (default 1 sec).
    while (!Serial) {;}             //Wait until Serial wakes up
    Serial.println("ready");
}

void loop() {
  int step_count = 0;

  
  while (!Serial.available() ){;}            //Loop and do nothing until there is a serial character received.
  while(Serial.available()){                //Receive bytes and parse them into an integer.
  int target = Serial.parseInt();             //this function finds the integer in the bytes, ignoring commas, spaces, returns, etc....
  
  int step_dir = 1;                 //step_dir determines whether to step +,-, or 0.
  
    while(!(step_dir == 0 )){         //This loop continues until the target is reached.
    if (target - step_count > 0) step_dir = 1;
    else if (target - step_count < 0 ) step_dir = -1;
    else step_dir = 0;
    step_count += step_dir;               //modify accumulated steps accordingStepper1.step(-step_dir);
    Stepper1.step(step_dir);
    Stepper2.step(-step_dir);
    delay(10);
    }
  }
}

Testing

Now I can finally get to testing. I needed to figure out how many steps it takes to fully open my curtain. However, things went awry during the very first test.

Troubleshooting

I smelt smoke coming from the machine, and immediately afterwards, one of my stepper motors suddenly stopped turning. After that, it kept spasming and doing random rotations.

Motor Malfunction

I restarted the metro a bunch of times and even switched the motor drivers, but to no avail.

I came back the next day to solve the problem. I noticed that the Atmel chip on the metro was always burning hot. Furthermore, the metro stopped receiving uploads altogether. The board would just turn off whenever I tried to upload my code. I was too frustrated to continue, and I decided to wait and get help during Monday's lab session.

After talking with Nathan and Victoria, I switched my microcontroller to an Arduino Uno, which is the only spare microcontroller I had. At first, nothing happened, but after replacing the motor driver with a new ones, the stepper motor finally turned!

I think the problem was a combination of the metro board and a fried motor driver. It took so long to figure it out since I kept fixing one or the other, not both issues.

Anyways, I got back to testing and found that 3000 steps is enough to fully open the curtains!

Result

Finally, it worked!

Automatic Curtain

Malfunctions

My happiness didn't last long. Soon after that video was taken, my other motor driver burnt out as well. This time I had no replacements.

Furthermore, the string I attached to the motor was too thick, and it kept skipping steps.

String Skipping

Future Solutions

Unfortunately, I don't have enough time to get new supplies and improve this machine before the due date. However, I will definitely improve this and share the results later.

My first improvement will be using the A4988 motor driver, which should be less susceptible to burnouts.

After that, I will use nylon threads as my string. These will be thinner than my current ones, and so they will skip steps less frequently.

Future Code

After these improvements are implemented, I will be able to perform recurring actions. I can then use the following code to open and close the curtains at specific times.

I utilized the Time library. My reasonings are in the comments.


#include <Stepper.h> // Stepper Library
#include <TimeLib.h> // Time Library

const int stepsPerRevolution = 200;  //200 for our steppers.

// initialize the stepper library for two steppers:
Stepper Stepper1(stepsPerRevolution, 11, 10, 9, 8);
Stepper Stepper2(stepsPerRevolution, 7, 6, 5, 4);

// Initialize parameters
const int STEPS_NEEDED = 3000;
const int WAKE_UP = 10; // 10 AM
const int SLEEP = 23; // 11 PM

void setup() {
    Serial.begin(9600);
    setTime(hr,min,sec,day,mnth,yr); // Will have to synchronize this whenver I run this program
}

void loop() {
    if (hour() == WAKE_UP) { // Hour() returns the current hour (0 - 23)
      open();
    } else if (hour() == SLEEP) {
      close();
    } else { // writing "HIGH" to all motor pins will turn them off
      digitalWrite(11, HIGH);
      digitalWrite(10, HIGH);
      digitalWrite(9, HIGH);
      digitalWrite(8, HIGH);
      digitalWrite(7, HIGH);
      digitalWrite(6, HIGH);
      digitalWrite(5, HIGH);
      digitalWrite(4, HIGH);
    }
}

void open() {
    int step_dir = 1;                 //step_dir determines whether to step +,-, or 0.
    int step_count = 0;
  
    while(!(step_dir == 0 )){         //This loop continues until the target is reached.
    if (STEPS_NEEDED - step_count > 0) step_dir = 1;
    else if (STEPS_NEEDED - step_count < 0 ) step_dir = -1;
    else step_dir = 0;
    step_count += step_dir;               //modify accumulated steps accordingStepper1.step(-step_dir);
    Stepper1.step(step_dir);
    Stepper2.step(-step_dir);
    delay(10);
    }
}

void close() {
    int step_dir = 1;                 //step_dir determines whether to step +,-, or 0.
    int step_count = 0;
  
    while(!(step_dir == 0 )){         //This loop continues until the target is reached.
    if (STEPS_NEEDED - step_count > 0) step_dir = 1;
    else if (STEPS_NEEDED - step_count < 0 ) step_dir = -1;
    else step_dir = 0;
    step_count += step_dir;               //modify accumulated steps accordingStepper1.step(-step_dir);
    Stepper1.step(-step_dir);
    Stepper2.step(step_dir);
    delay(10);
    }
}