Sunday, February 9, 2014

A multifunction remote control for the Sony-NEX-7 and other cameras.

This is an Arduino-based infrared remote control, able to control a NEX-7 Sony camera.  You can use this to take photos of wildlife while you are lurking in the distance, or to take time-lapse videos of different subjects.  With a few changes, it can be adapted to any camera with infrared remote capabilities.  The toughest part in adapting it to other cameras will be finding the IR sequence your camera understands.  Extensive information on how to hack your camera remote can be found at http://www.righto.com/search?q=IR and http://learn.adafruit.com/ir-sensor
I am indebted to these two scholarly articles, from which I have derived the code for the IR LED.

This remote can carry out the following tasks:

a)    Activate the camera shutter when motion of a warm body occurs in the field of the motion sensor.
b)   Activate the camera shutter when a light sensor is triggered by a standard red light laser pointer.
c)    Activate the camera shutter at fixed intervals for time lapse photography (intervalometer).

Each function can be selected through a 16 position rotary switch.

The hardware assembly is completely of my design, but the code is an adaptation of several sources that I wish to thank.


Fig 1. The Sparkfun shield, installed in the project box. The Arduino is underneath, but cannot be see in this view.

The main components:
a)    Arduino Uno rev 3.
b)   Sparkfun prototyping shield: (https://www.sparkfun.com/products/9900)
c)    Sparkfun PIR motion sensor: (https://www.sparkfun.com/products/8630)
e)    Sparkfun 16 positions dip switch and knob: https://www.sparkfun.com/products/10064
f)     One IR 950 nm LED from RadioShack:  http://www.radioshack.com/product/index.jsp?productId=2062565
g)    One generic red LED
h)   Translucent red plastic sheet
i)     Loc-Line Coolant Hose Assembly Kit (can be found at Amazon or other sources).
j)     Six 10 KOhm resistors and one 39 Ohm resistor
k)    Soldering tools, wire, multi-meter, screw, glue, a plastic project enclosure box etc.


The circuit:
The PIR sensor is connected as follows: signal to digital pin 2, power to 5V on the Arduino, ground to ground on the Arduino. A 10 KOhm resistor connects signal to voltage.  There are two main types of PIR sensor, one goes HIGH when motion is detected, the other goes LOW when motion is detected). The wiring is different (and obviously the code) so you need to know what you are using.  The Sparkfun is of the second type and explained here:  http://bildr.org/2011/06/pir_arduino

The PIR sensor installed on the exterior of the plastic box.  I accidentally cracked one of the screw holes...

The light sensor comes with a kit with its own resistor. I connected its power wire to 5V on the Arduino, the ground wire to wire and its signal wire to analog pin 3.  This kit works the opposite way as bare light sensing diodes, in that the higher the light level, the lower the signal.  You can certainly use a standard light sensing diode. In this case you would connect one end to 5V, the other end to both analog pin 2 AND ground through a 10 KOhm resistor.  In this configuration, the sensor provides higher input to the pin with higher ambient light.  I have used the kit only because of its case that allows for very solid mounting (see photo), but the price is some $20, compare with $2-3 with the diode+resistor.  I have covered the diode with 2 layers of translucent red plastic sheet (not shown here). This trick dramatically reduces the passage of ambient (white) light, while allowing almost complete passage of the red laser light in the pointer, preventing activation of the sensor in sunlight.  The sensor is then activated remotely with a laser pointer. The distance varies with the power of the pointer. Aiming may be a little tricky in sunlight.

The light sensor installed on the box.

The IR LED is connected to digital pin 8.  In my implementation I soldered a long wire to the voltage (anode) end of the LED. I then soldered the resistor followed by a long wire on the ground (cathode) end of the LED. The anode is connected to analog pin 8.  I passed both wires through the coolant hose and glued the LED on the neck of it.  This produces an IR LED mounted on a flexible arm that allow to point the LED toward the IR sensor on the camera no matter the direction the motion sensor is facing.  This is critical in open spaces, where rebound IR signal from walls cannot be expected to help. 

 The flexible Coolant Hose, you can see the IR LED glued through a simple washer to the top. 


The Hose is secured to the interior of the box.


The rotary dip switch has six pins: two for voltage, and four state pins. Connection are as follows: voltage to voltage pins, pin 1 to Arduino digital pin 4, pin 2 to Arduino digital pin 5, pin 3 (also called 4 in the reference sheet) to Arduino digital pin 6, and pin 4 (also called pin 8 in the reference sheet) to Arduino digital pin 7.  Each of the state pins is connected to ground through a 10 KOhm resistor.

The switch is soldered with its connection to a small circuit board. 

The switch (small dented pin) is passed through the box and secured to it. 

A knob over the switch now allows the switched to be easily turned. I am in the process of designing a decal that will indicate the function of each position of the knob.

A red LED is connected to Arduino digital pin 13 and used to signal activation of the IR LED in debugging.

Second thoughts:
The red LED should be on the same side of the box as the light sensor.
Being able to use a smaller enclosure box would also be nice.
A potentiometer could be used to regulate the interval in the timelapse routine.

Results:
Here is an example photo I obtained with an earlier version of the device:


And here https://www.youtube.com/watch?v=Vr9iEtYYmJ4, an example of time lapse (interval 30 seconds).

The Code:
Below is the code.

Disclaimer: I am just a beginner, so I am sure some experts will find better ways to code for this.  In particular the transformation of the dip switch readings into a string may be frowned upon. Oh well, it works...

const int laserSensor = A3;
const int redLed = 13;
int lapse;
int laserValue;
int IRledPin =  8;
int motionSensor = 2;
const int switchPin1 = 4;     // the number of the switch’s pin
const int switchPin2 = 5;     // the number of the switch’s pin
const int switchPin3 = 6;     // the number of the switch’s pin
const int switchPin4 = 7;     // the number of the switch’s pin
String Fin ; // this string will contain the switch values

void setup(){
  Serial.begin(9600);
  pinMode (laserSensor,INPUT);
  pinMode (redLed,OUTPUT); // this is the signal LED
  pinMode (motionSensor,INPUT); // motion sensor pin
// initialize the switch pins as an input:
  pinMode(switchPin1, INPUT);
  pinMode(switchPin2, INPUT);
  pinMode(switchPin3, INPUT);
  pinMode(switchPin4, INPUT);
 //Initialize IR LED pin. 
pinMode(IRledPin,OUTPUT);
   

 
}
void loop(){
// reads the state of the switch’s individual pins and "strings” them:
String S1 = String (digitalRead(switchPin1));
String S2 = String (digitalRead(switchPin2));
String S3 = String (digitalRead(switchPin3));
String S4 = String (digitalRead(switchPin4));
// generates the combination string:
 Fin =  (S1+S2+S3+S4);
 if (Fin=="0000"){ //the decision tree starts here
   motion();}
   else if (Fin=="1000"){
     laserSense();}
     else if (Fin=="0100"){
       timeLapse(0);}
       else if (Fin=="1100"){
       timeLapse(3000);}
       else if (Fin=="0010"){
       timeLapse(6000);}
       else if (Fin=="1010"){
       timeLapse(12000);}
       else if (Fin=="0110"){
       timeLapse(30000);}
       else if (Fin=="1110"){
       timeLapse(60000);}
       else if (Fin=="0001"){
       timeLapse(15*60000);}
       else if (Fin=="1001"){
       timeLapse(29*6000);} 

}
// This procedure sends a 38KHz pulse to the IRledPin. 
// for a certain # of microseconds. We'll use this whenever we need to send codes
void pulseIR(long microsecs) {
  // we'll count down from the number of microseconds we are told to wait

  cli();  // this turns off any background interrupts

  while (microsecs > 0) {
    // 38 kHz is about 13 microseconds high and 13 microseconds low
   digitalWrite(IRledPin, HIGH);  // this takes about 3 microseconds to happen
   delayMicroseconds(9);         // hang out for 10 microseconds
   digitalWrite(IRledPin, LOW);   // this also takes about 3 microseconds
   delayMicroseconds(9);         // hang out for 10 microseconds

   // so 26 microseconds altogether
   microsecs -= 26;
  }

  sei();  // this turns them back on
}

void SendChannelUpCode() {
  // This is the code for the shutter release for SONY NEX-7
pulseIR(2400);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(11000);
pulseIR(2400);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(600);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(600);
pulseIR(1200);
delayMicroseconds(11000);


for (int i =0; i<5;i++){//sends 5 blinks to the red led after each activation of the IRLED
digitalWrite(redLed, HIGH);
delay(9);
digitalWrite(redLed, LOW);
}}
void laserSense(){ // this is the function that senses the laser signal
  laserValue = analogRead(laserSensor);
  if (laserValue<30){
  SendChannelUpCode();
    }
    }
void timeLapse(int lapse){ // this is the time lapse routine
  SendChannelUpCode();
  delay (lapse);
}
void motion(){//this is the motion sensor routine
  boolean movement = digitalRead(motionSensor);
  if (movement == LOW) {
 
  SendChannelUpCode();
  delay(1000); //this delay is introduced to avoid the second ("echo") discharge from the PIR sensor.
               //For reasons that I do not understand the sensor goes off twice or more with one
               //pass of, say, the hand.
  }}