Automatic Blinds Project

The project is in V 1.0! Here's a pic of the setup:

The blue parts I had to print from my university's 3D printer, which is a MakerBot Replicator 2, I believe. One mounts the servo to the wall next to the window (with the help of some "Picture Hanging Strips" from Home Depot) and one connects the servo arm to the blinds rod.

It works. Kind of.

Problems I encountered:

  • At first I just stuck a "Picture Hanging Strip" right on the servo. This didn't provide enough support for long and the servo would sometimes peel off the wall as it tried to open the blinds. I solved this by printing the blue Servo Mount and putting TWO strips on the back of it. This seems to solve the peeling issue.

  • (BTW, the Arduino enclosure is attached to the wall with just one of these picture hanging strips and that seems to work just fine.)

  • The Servo Mount I originally printed wasn't sturdy enough--the triangular rod that's perpendicular to the wall (out of which emerge the two circular rods that allow the servo to be mounted) broke off. This was an easy fix; I printed one with a thicker triangular rod.

The only problem left to fix seems to be that the servo seems to be weakening over time. I tell it to turn for 15 seconds and during those 15 seconds it doesn't open or close the blinds as much as it did a few weeks ago.

So in the long-term, it looks like I'll need a more durable solution--unless this is just a breaking-in period for the servo. Maybe someone with more servo experience could tell me what to expect? Will the servo continue to weaken over time or will it reach a plateau?

OK, everyone, you were right--It's not good enough for the Arduino to have a routine that it blindly executes--it needs some way of knowing the state of the outside system.

Been running into two problems recently:

  1. Random resets -- one morning, the Arduino seemed to be executing the routine at the wrong time. The only explanation for this is that it lost power, and then it regained power, thereby starting its clock at the point I had custom-programmed. What's interesting here is that my other appliances hadn't been reset (for example, my alarm clock hadn't reset its time). Open question: Is the Arduino Uno vulnerable to minute lapses in power input in a way that most appliances aren't?

Anyway, to fix this, I'd need to enable to Arduino to regularly check its time against an external, reliable source. This fits right in with an upgrade that would allow me to tell the Arduino to either open or close the blinds on command--which I plan to do with a Bluetooth shield and an Android app. That could be a while in the making yet.

  1. Eventual offsets in routine -- the routine I cooked up is vaguely functional, but it's inconsistent. It'll work fine once or twice, but eventually the blinds are a little too far open or a little too far closed. I've been fixing this by manually adjusting their position every so often, but there are reasons I shouldn't do this (it's wearing out the Servo's velcro strips, for one.) So I need to provide a way for the Arduino to know the rotational position of the blinds. Now's when I'll start looking into sail winch servos and such.

--

More generally: Now that I'm feeling a little more confident about my abilities, I may return to my original "raise/lower the whole blinds" design concept. In that case, I'll need a more powerful DC motor instead of the servo, and I'll of course need to print up some new parts.

Another update--the routine seems to be fairly consistent. I haven't had to manually correct the blinds' position in quite some time.

I figured out how to fix the reset problem. One night, I found my blinds trying to close at 1 AM or so, when they had already closed at 11 PM as usual. This explains the problem I was having where I found the blinds double-closed, which had cropped up a few times. I fixed this by adding a boolean "closed" to my program. This boolean gets set to "false" when the blinds close at 11 PM , and to "true" when they open. Not only that--the scheduled "close" and "open" routines are only run if the boolean is what would be expected. So, no more double-closing in the middle of the night.

Here's my current code.

/*
Making a continuous-rotation servo perform certain routines
at certain times of day

David Garrett, david.j.garrett@live.com

Notes:
My servo stops at value 95, not value 90 (Parallax continuous rotation servo, 2014) 
Any value less than ~85 or greater than ~105 seem to be equivalent
 --this is when the servo is unloaded mechanically, 
   haven't tested it loaded
Writing speed > 95 gives counterclockwise motion.
Writing speed < 95 gives clockwise motion.
^^^These are when looking at the arm's "face".

My Wiring:
green = ground
yellow = 5V
Orange = signal

From neutral (blinds level and open,) turn servo clockwise 5 times
to close blinds.

From there, turn counterclockwise 5 times to open them.

When open, the blinds are horizontal, level. 
When closed in the correct direction, the proximal edge goes down.

*/

#include <Servo.h> 
#include <Time.h>

Servo myservo;  // create servo object to control a servo
                // Write values from 0 to 179 to the servo. 95 means
                //  stop. 179 is full speed ahead. 0 is full speed
                //  backwards.
long openTime = 15625 * 10.0/4 ;               // How many milliseconds it takes to open my blinds
long closeTime = 10578 * 9.5/4 ;               // How many milliseconds it takes to close my blinds
long incrementTime = openTime * (3.4/50) ;     // A smaller chunk of time -- useful for making the blinds open over a longer
                                               //  time period
boolean closed = false;      // Answers the question, "The blinds are currently closed--true or false?"
                             // Change to "true" if they're starting out closed

void setup() 
{
  Serial.begin(9600);        // Allows for serial monitoring during potential troubleshooting
  myservo.attach(9);         // attaches the servo on pin 9 to the servo object 
  setTime(11,05,0,3,6,14);   // Hour, minute, second, day, month, year.
                             // (Change these numbers to reflect whatever time and date
                             //   it is when you plug the Arduino in.)
//  myservo.write(93);       // Use these two lines to make sure the blinds start in the right position based on
//  delay(openTime);         //    what time it is when you boot the Arduino (plug it in or reset it.)
  myservo.write(95);         // Tell the servo to hold still
}

void loop() 
{

//Useful for quick-ish testing:
/*
  if ( hour()==12 && minute()==00 && second()==03) {
    
    for (int j = 1; j<6; j++){

      //Test close direction:
      myservo.write(97);
      delay(closeTime);
      //myservo.write(95);
      //delay(100);  
      
      //wait for 2 seconds:
      myservo.write(95);
      delay(2000);
      
      //Test open direction.
        //Open 2/5 of the way:
        myservo.write(93);
        delay(2*openTime/5);
        //Then pause:
        myservo.write(95);
        delay(300);
        //Then open 3/50 of the way 10 times in a row, with pauses
        // in between, making 3/5 taken together and 5/5 of the way
        // all in all.
        
      for (int i=1; i<11; i++){
        myservo.write(93);
        delay(incrementTime);        
        myservo.write(95);
        delay(300);
      }
      
      myservo.write(95); //and stop.
      Serial.println("End loop");
      delay(2000);
    }
  }
*/


//FINAL CODE TO IMPLEMENT

  //OPEN the blinds at 9:45 am, if the blinds are currently closed:
 if (hour()==9 && minute()==45 && second()==0 && closed) {
    
      //Open 2/5 of the way:
      myservo.write(93);
      delay(2*openTime/5);
      
      //Then pause:
      myservo.write(95);
      delay(300);
      
      //Then open 3/50 of the way 10 times in a row, with pauses
      // in between, making 3/5 taken together and 5/5 of the way
      // all in all.
    for (int i=1; i<11; i++){
      myservo.write(93);
      delay(incrementTime);      //Open 3/50 of the way        
      myservo.write(95);         
      delay(90000);              //Pause in between
      
      
    }
    
    myservo.write(95);  //and stop, wait for closing time.
    closed = false;
  }
  //CLOSE the blinds at 10 PM:
  if (hour()==22 && minute()==0 && second()==0 && !closed) {
    myservo.write(97);
    delay(closeTime);
    myservo.write(95); //and stop.
    closed = true;
  }

}

I bought an HC-06 bluetooth module from fastTech.com, which came with a convenient set of 6 attached jumper cables for its 6 pins. I learned from this video ( - YouTube ) that I need to use a few resistors between the Arduino and the HC-06's RX ports to reduce the voltage so I don't fry the HC-06. That means I need a board to make a simple circuit on. I would like that board to fit in my enclosure.

I went to Radio Shack and bought a Proto Shield by Seeed Studio. I hoped it would provide the circuit-place I needed while also stacking on top of the Arduino nicely. Unfortunately, it doesn't fit within the enclosure in its current state. It's too wide. I may find a way to shave the side of it off so it will fit in. If I do end up being able to use it, I'll still need to do some soldering using my school's equipment. Bit of a hassle. Maybe I should just get

In the meantime, I need to figure out the code. I'll need to teach the Arduino to get info from the HC-06, and I'll need to teach my tablet to send info via Bluetooth to the HC-06.

Sorry if this has already discussed previously, but have you considered using an LDR as a light level sensor to control the blinds? It's very easy to do, and is very convenient if you want the blinds to open at dawn and close at dusk (or some fixed time relative to dawn/dusk).