Sunday, 16 July 2017

Photography Flash Trigger - Pt 1

Unfortunately, despite the seller's promises of a very quick ETA for the header pins I ordered at the beginning of the week, which were supposed to arrive Thursday or Friday, they have sadly failed to deliver - quite literally.

So this weekend's I2C LCD interface cable project was sidelined and I decided to do a little testing towards my photography project instead.  The idea of the project is to have an optical beam of some sort, either IR or visible light, which can act as a trigger for my camera flash when the beam is broken.  The aim being to be able to accurately capture water droplets as they hit a surface and break apart or bounce, etc.

To account for how far the drop needs to fall, I also want to have a variable resistor on an analogue input, that can be used to introduce a delay between when the beam is broken, and when the trigger occurs.With 1024 points on the analogue input scale, I figure that each point can be a millisecond and that will give me up to a second's worth of delay adjustment (or a little over).  The range I anticipate needing would most likely be no more than half a second, so I could possibly even go for 2 points per millisecond.

Of course the first step is to get the beam part working, and that's what I experimented with today.  I used Ken Shirrif's IRremote library to get the basic functionality, as I found a post on his blog with sample code for a basic beam-break  sketch using an IR LED and VS1838B receiver.  I know there is a newer library available, but it comes with warnings that it is not backwards compatible in some areas, and when I tried it with Ken's code - I got errors that I couldn't fathom so decided to just use his library instead.

A word of warning here - there are some conflicts between his library, and the Arduino RobotRemote library that comes as standard with the IDE install.  You will need to move or delete the RobotRemote library to use IRremote without errors.

There are 2 parts to the sketch - the first part is to set the IR LED constantly sending out a beam.  IR LEDs can draw a lot of power, and also generate heat - so the standard practice is to use a 50/50 pulse width modulation (PWM) at 38KHz.  All modern IR remote controls conform to this standard, though some older ones use 56KHz, but for the same reason.  The IRremote library takes care of this for you, so you don't need to work out all the PWM parameters and timings.
1
2
3
4
5
6
7
8
9
#include <IRremote.h>

#define PIN_IR 5    // Only seems to work when connected to pin 3 regardless of this setting
IRsend irsend;

void setup() {
  irsend.enableIROut(38);
  irsend.mark(0);
}

In his sample code, Ken has line 3 above set to PIN 3.  I wonder if this is more documentary than actual requirement, as when I tried to use pin 5, it would not work.  However, I plugged the LED into pin 3 and it worked despite my sketch having PIN_IR set to 5.
Line 4 instantiates an IRsend object, and calls it irsend.
Line 7 and 8 are in the setup() routine, so are only done once.  Line 7 sets the IR PWM frequency to 38 (KHz), and line 8 sends a 'mark' - which seems to be the IR equivalent of setting a digital output pin high.  The parameter on the mark action is a duration.  IR remotes work by sending on and off sequences, a bit like morse code, but with varying length ons and offs.  The duration parameter defines how many milliseconds the 'on' should last.  0 indicates that it will stay on indefinitely - which is just what I need for my beam.

The second part of the code concerns the receiver which senses the beam, and recognises when it is broken.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <IRremote.h>

#define PIN_DETECT 2
#define PIN_STATUS 13
IRsend irsend;

void setup() {
  pinMode(PIN_DETECT, INPUT);
  pinMode(PIN_STATUS, OUTPUT);
}

void loop() {
  digitalWrite(PIN_STATUS, !digitalRead(PIN_DETECT));
}

The detector pin is connected to pin 2, and declared as an INPUT
Pin 13 (the on-board LED) is set as an OUTPUT and used to indicate the status. It will flash on when the beam is broken. I also added monitoring via the Serial Monitor, and set a buzzer to beep, but for now, this is the pure IR code only.
Line 13 in the loop() routine is the key here - it checks the value on the detector pin (2) and uses that to control the on-board LED.  Under normal circumstances, the detector will be receiving a constant signal from the IR LED, but we don't want the on-board LED on all the time, so we invert the value, by preceding it with '!'  That way, the LED flashes on only when the beam is broken.

One thing I found with this sketch, is that the trigger actually occurs not at the point in time that the beam is interrupted, but at the point the beam is re-instated.  I could place my hand between the IR LED and receiver, and nothing happened... until I took my hand away and the beam was able to hit the sensor again.  For my application, I don't foresee this being a huge problem, but in other applications, it could be an issue.

The two extracts above were combined together and gave me the basic sketch, but I felt that an audible feedback would be useful, so I added a tone() command in the loop() routine.  Uh-oh, now my sketch will no longer compile!  Something about multiple definitions of vector7..???

I had no idea what this meant, but it seems many people have experienced it.  It is something to do with the on-board timers inside the ATmega328 chip, and how they are used in people's libraries.  There are only so many timers, and a lot of libraries - so it is inevitable that eventually, you will come across 2 libraries you want to use together, that are trying to use the same timer for different things. In my case, I think it was the timer being used to control PWM for the tone() command conflicting with PWM for the IR LED.  Luckily, I was able to find an alternate tone library (NewTone.h) that uses a different timer, and this got rid of my conflict.

So here is my complete code with Serial Monitor and bleeper included.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <NewTone.h>
#include <IRremote.h>

#define PIN_IR 5    // Only seems to work when connected to pin 3 regardless of this setting
#define PIN_DETECT 2
#define PIN_STATUS 13
#define PIN_TONE 9

IRsend irsend;


void setup() {
  pinMode(PIN_DETECT, INPUT);
  pinMode(PIN_STATUS, OUTPUT);
  pinMode(PIN_TONE, OUTPUT);
  irsend.enableIROut(38);
  irsend.mark(0);
  Serial.begin(9600);
}

void loop() {
  int beamState = !digitalRead(PIN_DETECT);
  digitalWrite(PIN_STATUS, beamState);
  Serial.println(beamState);
  if(beamState == 1) {
     NewTone(PIN_TONE,750,250);
  }
}

I set it all up on the breadboard, and it worked OK, but I really wanted the LED and sensor on a longish lead so that the Uno and power, etc, can all be far away from any water splashing.  So, I've now wired them onto a half meter length of 6 core cable, with two cores going to the LED and three to the sensor, and terminated them onto a new little DIY break-out board for convenient connection to the breadboard.

However, having got this far, I am not convinced that the IR LED and Receiver is going to be the right solution.  It does not seem to react very quickly at all... I can easily pass my finger between the LED and sensor and it not trigger the beep or flash the LED on pin 13.  I am also not convinced that a water droplet will provide enough of a barrier to the IR light to actually interrupt the beam in the first place.

Supplemental - Well, what do you know?  It actually works, well, to a degree anyway... The somewhat shaky hand held alignment of the LED and Receiver was introducing a lot of false triggers, but when I could hold them still enough relative to each other on either side of a dripping tap, I was rewarded by a fairly consistent beep... beep... beep!  This means I would need to jury-rig some kind of frame to hold the two devices in alignment to each other, and also be able to place that securely in position around the dripping tap.  However, this is just the first of a few alternative ideas I want to try, the next being a reflective beam contact, as opposed to a beam break - so I will arrange the sensor and LED adjacent to each other both facing in the same direction, but separated by a barrier, the idea being that as the water drop passes, it reflects the IR beam back to the sensor.  It should be easier to construct a rig for this arrangement - if the concept works.

By the way - I had a surprise package arrive from China today - the replacement MB102 PSU whose regulator became deregulated.

No comments:

Post a Comment