sábado, 18 de enero de 2014

An Arduino Based Shannon Machine

A Shannon machine has only one function: to switch itself of. The irony of its simplicity has captured me for long, and when I started tinkering with Arduino this was one of the first projects that came to my mind. 

 As a starter, have a look at the video of the finished project, and keep on reading if you are interested.



I started the project with an Arduino Nano, the Chinese copies are around 5 euro these days. Then I realized that it would not fit in the box if I also had to include the 9V battery. So I switched to an AtTiny 85, a microcontroller from Atmel with a very small form factor and just 8 pins. They are ideal if your project is tight on space and/or budget and are easily programmable from the Arduino environment, just follow these instructions

The Tiny must be fed at 5V, so I added the 7805 voltage regulator. Maybe a 78L05 would do, but the motor is eating more than 300mA when it is closing the switch and I felt more comfortable with the extra dissipation that the 7805 provides.

As a motor I am using a microservo. These kind of motors can turn 180 degrees and have a built in position control. They are really easy to wire: red cable for power, black or brown cable for ground and yellow cable to send the commands. Arduino has the <Servo.h> library which allows you to send commands directing the motor to a certain angle. If you are using the AtTiny, you will have to download and use <SoftwareServo.h> instead.


The shopping list


  • A box, some 3 euro 
  • SG90 microservo, less than 4 euro at dealExtreme
  • 9V battery and its connector
  • microcontroller AtTiny 85, 1 to 1.5 euro at RS or other online shops
  • Switch
  • LED
  • 7805 voltage regulator
  • 4.7 and 0.1 microfarad capacitors
  • 470 and 10K ohm resistors

The Schematics



or in a more realistic representation thanks to Fritzing:





The Arduino code

//Shannon Slow Detach Attiny85

// Carles Flotats, December 2013

// It reads the switch (pull upped). If activated, the led 
// is lit, the motor is moved from the STOPPOS degrees
// starting position until the switch is off, the led is 
// unlit and the motor returns to POS degrees

// Evolves from Shannon Complete Attiny85 to make it slower 
// by sending the degrees one by one 
// Detach evolution: to avoid inestability in the servo, 
// it is detached every time it finishes a movement
//Shannon Machine on an AtTiny 85


#include <SoftwareServo.h>  
// has been modified from the downloaded one to use Arduino.h 
// instead of Wsomething.h
// If you are using an Arduino instead of an AtTiny, you better use <Servo.h>
 
SoftwareServo myservo;  // create servo object to control a servo 
                
 

int switchVal=1; //variable to store the state of the switch

int ledPin=2;  // pin 2, output to the resistor and the status led
int servoPin=1; // pin 1, output to the servo control, yellow cable
int switchPin=0; // pin 0, input from the switch, pull up configuration

int stopPos=53;   // position in degrees of the motor while resting
int currentPos=stopPos;

 
void setup() 
{ 
  myservo.attach(servoPin);  // attaches the servo on pin 9 to the servo object 
  myservo.write(stopPos);    // initialize the servo to the stop position
    for (int i=0; i <= 20; i++){  // softwareServo::refresh must be executed 
                                  // every 50 ms to avoid unstabilization
    delay(25);
    SoftwareServo::refresh();
  }
   
  myservo.detach();
  
  pinMode(ledPin, OUTPUT);
  pinMode(switchPin, INPUT);
  
  digitalWrite(ledPin, LOW);
  
} 
 
 
void loop() 
{ 
  while (switchVal==1){              //if the switch is not activated, the loop is 
    switchVal=digitalRead(switchPin);// not broken and the rest of the program is not executed
    
    delay(15);
  } //end of while

  digitalWrite(ledPin, HIGH);

   
  delay(500);
  
  myservo.attach(servoPin); 
  
  while (switchVal==0){
    currentPos=currentPos++;
    myservo.write(currentPos);
    delay(10);
    SoftwareServo::refresh();
    switchVal=digitalRead(switchPin);
  } // end of while
  
  digitalWrite(ledPin, LOW);
  
  currentPos=stopPos;  
  
  for (int i=0; i <= 20; i++){  //softwareServo::refresh must be executed every 50 ms to avoid unstabilization
    delay(25);
    SoftwareServo::refresh();
  } //end of for
   
   
    
   myservo.write(stopPos);
   
   for (int i=0; i <= 40; i++){  //softwareServo::refresh must be executed every 50 ms to avoid unstabilization
    delay(25);
    SoftwareServo::refresh();
  } //end of for 
  

  myservo.detach();
  switchVal=1;
 
} // end of loop