Showing posts with label IR Sensor. Show all posts
Showing posts with label IR Sensor. Show all posts

Tuesday, 25 July 2017

Photography Flash Trigger - Pt 2



Last night, I did a bit more work on the Flash Trigger project.  The first thing was to remove the testing printouts to the Serial Monitor, and replace it with the LCD, and then I mounted the receiver and LED on either side of a bit of card to try it out as a reflective receiver.  That was much easier to keep lined up with the dripping tap.


I've modified the loop() logic so that when the beam is interrupted, this triggers a quick beep, puts a message on the LCD, and starts a 3 second countdown. During the countdown period, the LED (on pin 13) will still flash to indicate when the beam is broken, but nothing else will happen.  After 3 seconds, it all resets, and the trigger's ready to go again.  I also added a counter to keep track of how many times the trigger is.... well, triggered.  The latest version of the code looks like this...

 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <NewTone.h>
#include <IRremote.h>
#include <LiquidCrystal_I2C.h>  
  
#define PIN_IR 3    // Documentary value only - Pin 3 (OC2B) is hard-coded in the library.
#define PIN_DETECT 2
#define PIN_STATUS 13
#define PIN_TONE 9

// Instantiate objects
IRsend irsend;
LiquidCrystal_I2C lcd(0x3F,20,4);

// set up global variables
int triggered = 0;
long trigMs = millis();
int trigCount = 0;

void setup() {
// Set pins as IN or OUT
  pinMode(PIN_DETECT, INPUT);
  pinMode(PIN_STATUS, OUTPUT);
  pinMode(PIN_TONE, OUTPUT);

// Put prompt on display (Coordinates = col 0-19, row 0-3)
  lcd.begin();
  lcd.setCursor(0,0);
  lcd.print("IR Beamer waiting...");

// Start the IR LED sending  
  irsend.enableIROut(38);
  irsend.mark(0);
}

void loop() {
  // Check beam and update LED in real time
  int beamState = !digitalRead(PIN_DETECT);
  digitalWrite(PIN_STATUS, beamState);

  // If newly triggered...
  if(beamState == 1 && triggered == 0) {
    // set flag and note the time
    triggered = 1;
    trigMs = millis();
    trigCount++;

    // beep
    // NewTone(PIN_TONE,750,250);  // The beep gets quite annoying

    // update LCD
    lcd.setCursor(10,0);
    lcd.print("TRIGGERED!");
    lcd.setCursor(1,1);
    lcd.print("(Counter=");
    lcd.print(trigCount);
    lcd.print(")");
    lcd.setCursor(1,3);
    lcd.print("resets in 3 seconds");
  }

  // Once triggered...
  // If 3 seconds have passed, then reset
  if(triggered == 1 && (millis() > (trigMs + 3000))) {
    lcd.setCursor(10,0);
    lcd.print("waiting...");
    lcd.setCursor(1,3);
    lcd.print("                   ");
    triggered = 0;
  }
  // If 2 seconds have passed, update countdown  
  else 
  if(triggered == 1 && (millis() > (trigMs + 2000))) {
    lcd.setCursor(11,3);
    lcd.print("1");
    lcd.setCursor(19,3);
    lcd.print(" ");
  }
  // If 1 second has passed, update countdown  
  else 
  if(triggered == 1 && (millis() > (trigMs + 1000))) {
    lcd.setCursor(11,3);
    lcd.print("2");
  }
}


I checked it out with the tap, and it was working pretty well, as long as it was within about 3-6" of the drips.  When IR remotes work from the sofa to the TV on the other side of the room, I was quite surprised that the range on my little contraption is only a few inches, but it is good enough for the particular job I have in mind.
The next step is to link the trigger action to an actual external device via a photocoupler - and then finally, introduce a delay.

By the way, the header pins that I ordered turned up at the end of last week, and the supplier also sent me a replacement set in case the originals had gone missing, and they turned up this morning.
Also in the post this morning was part 1 of my regulated power supply project - the buck converter - which has arrived 2 days before the estimated timeframe!  I must connect that up to some of my supplies and give it a bit of a test before I leave feedback for the seller.

With all these envelopes turning up, I felt a little like Julian Ilett and his " It's Postbag" videos on youtube.  Speaking of which, I was a little concerned when I found he has done a video about 'fake' LM2596 boards exactly like the one I ordered from ebay... thankfully, it turned out that what he was describing was sellers claiming to be selling the High Voltage (HV) version of the LM2596 which is rated at up to 60VDC input, but only putting the standard LM2596 (relabelled to look like the HV version) on the board, which is rated to 40VDC, or putting a fake 65V capacitor on the input side of the circuit (looked like the standard 50V cap with overprinting) - so the boards worked OK up to around 40-45V as per the design of the standard components, but then started behaving very strangely, and sometimes smoking gently, at anything higher.  Hopefully, as I have bought the standard 40V model, with the intention that it will never experience inputs above around 20VDC, there should not be a problem...

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.