Beginner An Idiots guide: DIY Water Drop Controller with Arduinos and stuff.

I've been having trouble getting repeatable results....I can get a nice collision image perhaps one or two times in ten attempts, but I'm not sure why I can't get the same style of collision with every image taken.

Your dripper code, triggering the drip & the camera delay is all done from one button push. If the drip is a bit sluggish to drop, the flash will fire earlier than had the drip been a bit nippier to drop. Also triggering the camera, rather than the flash adds latency.

You could try splitting the camera shutter and flash firing. Operate the camera shutter immediately and the flash after the delay.

Another alternate is to separate the timing. Drips can be fired as per your code, but time the firing of the flash from when the first drop breaks a light beam. You could use a photo-interrupter (they do ones with a wide gap) or use a separate IR LED and transistor.

Have fun & don't mix up 5V, 3.3V and 12V :eek:)
 
@GarethB Good work :eek:)

Have finished building my little digital readout for the Hiviz Multitrigger3 and Astrosplash. Wil post a piccy when plastic the LCD holder arrives from China & I can mount it onto the Hiviz.

Have also finished building my Binford 2000 Drip-o-Matic (anybody remember Tim-Tool-Time-Taylor?) It is just a MDF frame to hold bottle, drippers etc, that can be adjusted in all directions. I'm fed up with using light-stands and boom arms. Piccy to follow.

Waffling onto other things,
When making a sound or light activated trigger with Arduino, it never knows when the trigger will happen and could be doing time consuming things like updating the LCD or maths. The delay starting could be delayed or the trigger input missed completely.
I have bashed up some quick code using an interrupt to detect an input, which in turn starts the delay timer immediately.
Happy to post it here. Maybe we need to start a new thread for delay timers, as we have rather taken over Garath's fine building a dripper blog :eek:)

Many thanks Bill.
I'd be very interested to see your code Bill, I struggle with coding and I would definitely find it helpful, if it's not too much trouble.
And please feel free to post images of your Hiviz system too when it's finished.

In the meantime, here is a link to a simple sound operated delay in case peeps want to mess about with it
The sound module used are 99p on ebay.
You could probably get away with adding an input pot for the user to add a delay, but if starting to get clever with LCDs, the time between triggering & delay starting would start to vary too much.

https://petapixel.com/2017/05/10/build-simple-sound-trigger-high-speed-photos-Arduino/

Bye for now :eek:)

Thanks for the link Bill, I came across that tutorial when I was putting together my very simple sound trigger.
It hasn't progressed any farther past the basic prototype stage yet, but it seems to work quite well.
I'm using a sound module which I sourced from....you guessed it BITSBOX!
Likewise mine cost about a quid or so, and I'm looking forward to building something over the coming months.

Your dripper code, triggering the drip & the camera delay is all done from one button push. If the drip is a bit sluggish to drop, the flash will fire earlier than had the drip been a bit nippier to drop. Also triggering the camera, rather than the flash adds latency.

You could try splitting the camera shutter and flash firing. Operate the camera shutter immediately and the flash after the delay.

Another alternate is to separate the timing. Drips can be fired as per your code, but time the firing of the flash from when the first drop breaks a light beam. You could use a photo-interrupter (they do ones with a wide gap) or use a separate IR LED and transistor.

This makes sense Bill, I can see where I might have delay issues with a camera only trigger....I will give some serious thought to redesigning it to include a separate flash trigger too.
I like the idea of using a photo-interrupter, Martyn Currey talks about these in his tutorials for Arduino water drop controllers....sounds very interesting.

Have fun & don't mix up 5V, 3.3V and 12V :eek:)

:LOL:

This is a mistake that I have made, and will only make once!!!;)
 
Timers, Interrupts & Delay timer

Hi folks, to hijack Gareth's thread (sorry Gareth :eek:) work starts to make a delay timer that can be activated by sound, breaking a light beam, or whatever else we dream up. This could then be integrated with the dripper code., or be a stand alone project.

The first thing we need is a countdown timer, without using the delay() function. Luckily for us, the Arduino already has a built in 16bit hardware timer. Even more lucky is that there is a library available for us to use, rather than having to write to the microcontroller registers directly.

To download the library, follow the link below. Click on 'download' to download the library to your pc.
The library must now be added to the IDE. Open the Arduino IDE on your pc, then select the menu item -sketch - Include Library - Add .Zip Library. Then point it to the downloaded file.

https://github.com/PaulStoffregen/TimerOne

OK, now the library is loaded, we can open an example program.
In the IDE, select the menu item File - Examples - TimerOne - Interrupt
Note this will be right at the bottom of the examples list.
So we should now have the example code as shown below. Load it to your Arduino and the LED should blink rapidly.

Exciting? Not really. However if we understand how this code is working, we can develop it for our delay timer.
Timer1 is loaded with a time of 150000 microseconds, or 0.15 of a second
Timer1 is then attached to an interrupt called blinkLED.

The main program can be put in the void loop, doing what ever we want, printing to LCD or dripping blobs of water for example.
However, every time out Timer1 counts to 150000 microseconds, the program will finish the line of code it is executing and jump to the bit of code called blinkLED.
It will then run this code and then jump back to the main loop at the next line of code.

Smart eh? we can now do two different things at the same time (almost) blink an LED for a certain time period and run code in the main loop.

Have a play with the above.

To progress the project, we need a way to,
allow the user to set the time delay
blink the led once only (i.e take one photo)
have an input to trigger the delay, for example from a sound or breaking a light beam, or a simple push button.

...to be continued in the next post......



Code:
#include <TimerOne.h>
// This example uses the timer interrupt to blink an LED
// and also demonstrates how to share a variable between
// the interrupt and the main program.

const int led = LED_BUILTIN;  // the pin with a LED
void setup(void)
{
pinMode(led, OUTPUT);
Timer1.initialize(150000);
Timer1.attachInterrupt(blinkLED); // blinkLED to run every 0.15 seconds
Serial.begin(9600);
}

// The interrupt will blink the LED, and keep
// track of how many times it has blinked.
int ledState = LOW;
volatile unsigned long blinkCount = 0; // use volatile for shared variables
void blinkLED(void)
{
if (ledState == LOW) {
ledState = HIGH;
blinkCount = blinkCount + 1; // increase when LED turns on
} else {
ledState = LOW;
}
digitalWrite(led, ledState);
}

// The main program will print the blink count
// to the Arduino Serial Monitor
void loop(void)
{
  unsigned long blinkCopy;  // holds a copy of the blinkCount
  // to read a variable which the interrupt code writes, we
// must temporarily disable interrupts, to be sure it will
// not change while we are reading. To minimize the time
// with interrupts off, just quickly make a copy, and then
// use the copy while allowing the interrupt to keep working.
noInterrupts();
blinkCopy = blinkCount;
  interrupts();
  Serial.print("blinkCount = ");
Serial.println(blinkCopy);
delay(100);
}
 
...ok folks, here is a development of the code. I tried to keep it short to enable people learning c++ to follow.

User input via a potentiometer will allow the user to set the pause time between trigger input and flash firing.
The built in LED will light for the duration of the pause and pin D10 will go high (+5volts) after the pause, intended to fire a flashgun.

You will need to wire a pushbutton from pin D2 to ground. To play around with, this will be ok, however your finished circuit must debounce inputs, else havoc is caused.
For an article on bouncing switches and how to debounce, follow the link.
I would recommend the second circuit shown after 'FIX IT IN HARDWARE' and to order the components on ebay now. The 74HC14 ICs are 5 for 99p. Each IC has six inputs.
https://hackaday.com/2015/12/09/embed-with-elliot-debounce-your-noisy-buttons-part-I/

A potentiometer needs to be connected to A0. This is the user delay input. Centre leg to A0, outer two legs, one goes to +5v, other to 0volts
An LED can be connected to pin D10, via a resister of approx. 330 Ohm to 0volts

There are two interrupts being used. 'trigger' detects a trigger input on pin D2. It sets the timer running, which is the pause before flash firing.

'blinkLED' is called when Timer1 is set and when Timer1 expires. So when Timer1 is set (by the trigger ISR) 'blinkLED' will be called and turn on the LED.
When Timer1 expires, 'blinkLED' will again be called, which now turns off the LED, turns on output D10 and stops the timer.

Unless these two interrupts are called (due to triggering or timer) the code will just whizz round in the 'void loop' so we can do whatever we want here, print to LCD or screen, drop drips of water etc.
An interesting thing to note, interrupts will still work during a delay(). If the interrupt code can be executed during the delay period, the programmed delay time will not be extended. If the code runs longer than the delay() finish time, then obviously the next instruction will be a little bit late. So the trick is to keep interrupt subRoutines (ISRs) as short as possible, do not print or carry out complicated maths in them.

Note only D2 and D3 can be used as an interrupt input, so an LCD screen cannot be used with the code below. Don't worry for now, the final code will bump the LCD pins up.

- edit - deleted code
 
Last edited:
A note on Chines knock-off Arduino clones.
I say this as a warning, in case anybody is following this thread and buys a Chinese knock-off and is most disappointed that they cannot join the fun.

A genuine Arduino uses a Amtel 16U USB driver IC. The Arduino microcontroller already has the bootloader installed.
These work fine, with no issues. Driver installs on Win 10 x64.
The Arduino software (IDE) shows the board in the list of com ports (enabling the correct one to be selected)

Some of the better clone products also work fine. For example, I originally purchased the Elegoo starter kit. This has their own Uno clone.
Happily this uses the correct Amtel 16U driver IC and has the bootloader installed. All works great.

Now onto the great Chinese knock-offs.
The Nanos that litter Ebay & Amazon all show the header pins not to be soldered. They also state 'CH340 USB driver IC'
Despite the description stating they have a bootloader, they do not.
I also purchased a Mega 2560 from a UK seller. this again had the CH340 IC. Guess what, no bootloader & made in China.

What is the problem? Well without a bootloader on the Arduino you will not be able to communicate with it.
So unless you can load your own bootloader, it is junk.

Loading (or burning as people call it) a bootloader onto a Chinese clone is really easy if you already have a working Arduino.
It is all done from within the Arduino IDE. The files to load onto the Arduino are already there, in the examples tab.
The working Arduino is used to copy a bootloader onto the clone. There are loads of Youtube videos explaining the process.

A second way to load the bootloader if no working Arduino is available, is to purchase one of the many ISP programmers on Ebay or Amazon. Ensure it has a six wire cable. Again the great YouTube has loads of videos covering this technique.

If you are planning to use lots of Chinese knock-offs, or you just like playing, I can highly recommend
Nick Gammon's solution. I have a dedicated Nano loaded with Nick's code and made my own 6 way cable by cutting down an 8 way ribbon cable (butchery I know, but it is all I had. Ebay sell a 6 way cable for 99p) A cable is not actually needed, female to female jumper wires do the job, or even male-female if you hop through a breadboard.
http://www.gammon.com.au/bootloader

The next issue is loading the CH340 driver onto your pc to allow USB communication to the knock-off. For some it seems easy, for others not so.
Use Dr. Google to find the driver, often the Ebay sellers show the link in their description.
In fairness I think many reported issues are caused by the knock-offs not having a bootloader, so will not communicate until they do.

Unlike a genuine Arduino, the com port a knock-off is connected to, will not show up in the 'port' tab under 'tools' in the Arduino IDE.
So one has to go to device manager to see which one it is. Hopefully the driver should have installed correctly, else you will have a yellow triangle next to the port.

Once I realised none of these Chinese knock-offs have a bootloader, even if they say they do and to look in device manager for the com port, I have had no issues with any of the Chines clones.

Happy coding :eek:)
 
Thank you most kindly Bill (@billbillbill ) for the incredibly detailed advice....sorry I didn't respond sooner, it's a lot to take in, and I wanted to get a handle on it first!
The articles you have linked to are very interesting, especially the one regarding 'de-bouncing' switches.
So I have read that article with great interest and have bought a handful of the 74HC14 ICs which I am currently testing on a new prototype build.
Nothing to report as yet, but I've studied the characteristics of these chips and they seem fairly straightforward.
I'll be having a play with the code you posted soon too.(y)

I'll hopefully be trying to not only incorporate interrupts into the next evolution, but also I would like to implement some kind of menu system too.
I would like to design a triple valve system, each with the capability of dispensing multiple, timed drops...certainly three but perhaps four.
And I will be separating the flash from the camera controls too, and having them each on their own separate, time-adjustable system.
I could buy an Arduino Mega and have one big screen and a ton of pots etc, or I would prefer to be efficient and work with menus.
I've done some preliminary research, but it's much harder than it sounds!

Are there any easy-to-understand resources out there for simpletons like me?!:LOL:
Not forgetting that up until now, the only programming I've ever done was in BASIC, over 35 years ago, to wit:

Code:
10 PRINT "HELLO"
20 GOTO 10

I have an awful lot to learn!!
Maybe I'm trying to run before I can walk here....this may be a bit too advanced at my stage of learning!

Regarding your advice on Chinese knock-off Arduino clones, I had a bit of an issue with mine at first (Elegoo Nanos) but they seemed to work fine when I changed to the 'old bootloader'. Don't remember downloading anything....I just fiddled around until it worked - not very methodical or scientific but it worked out in the end!
Is this 'old bootloader' ok to use? It seems to work fine for me.
I'll probably stick with the Elegoos anyway, they seem decent, and robust....except when one accidentally puts 12 VDC through it!!:facepalm:
I'll be having a look at the 'Nick Gammon' solution however....forewarned is forearmed as the saying goes.

Once again Bill, many thanks for the time you've taken to post such good and detailed advice!(y)
It'll take me a while to understand the principles of 'the interrupt' but I'll keep at it.
 
haha, I like your basic programming. Reminds me of doing such things as a boy on shop demo computers.
I have a fully functioning delay-timer code that works with a uno/nano, happy to post here if wanted.

Was going to build some sound and break-beam triggers for the delay timer, however Ebay sell complete units, cheaper than I can by the individual components. They are pre-assembled on a little pcb with header pins, LED and logic to give a clean 0V/ 5V output. No need for debounce or Schmitt triggers. The sound sensor should work without modification. The collision avoidance sensor would need the IR LED un-soldered, so it can be positioned to point back at the PCB to create a beam, to be broken.

I have moved onto the Mega 2560. Simple reason it has far more IO and interrupts. Also, rather than using a separate protoboard for the components, a cheap development shell plugs straight on the top, so keeps everything neat & no jumpers between mega board and protoboard.
Have also switched to a four line 20 X 4 LCD with serial interface, so only 4 wires.

Looked at a menu system, using a rotary encoder. Idea being to cut down on the number of input pots required. However this has turned out to be such a faff, requiring two encoders, one for selection, other to change the value. This in turn needs 4 interrupts, loads of LCD code to move a cursor., highlight text & stuff.
I'm going to stick with a separate input pot for each adjustment, which will be.....
coarse time delay
fine time delay
timeout
drip 1 on time
pause time
drip 2 on time
pause time
drip 3 on time
Blimey, actually I think I might re-visit the idea of a menu system :eek:)

My Binford2000 has three solenoids, however they are ganged together. To program each separately will certainly be a challenge.

Using the old bootloader option in Arduino IDE is fine, it is there for compatibility. If you load a new bootloader onto the Arduino, it should allow the normal bootloader option. It is also a good idea to load the Uno bootloader onto a Nano. This will give you an additional 200k of memory to play with.

Right, my next step is to pinch your dripper code and add it to my delay timer code to make one splashtastic device.

bill.
 
Hi Folks,

Code below is for a delay timer. Seems to work ok. Note LCD pins (2,3,4,5 all moved up one to 2,4,5,6)
This makes pin 2 the input trigger.
Stick two pots on A0 and A1 which will give a coarse and fine adjustment. A third pot could be used to allow re-trigger timeout adjustment.
The on-board led lights for the length of the delay.
pin 12 gives a brief output on completion of the delay.


Code:
// ver 1.7 26 March 2019
//Note the word 'pause' used as 'delay' is a function & could cause confusion
//Note TriggerPin must be debounced, else it plays havoc. - look at link below...
//https://hackaday.com/2015/12/09/embed-with-elliot-debounce-your-noisy-buttons-part-i/
#define DEBUG false  //set to true for debug output, false for no debug ouput
#define Serial if(DEBUG)Serial
#include <TimerOne.h> // https://github.com/PaulStoffregen/TimerOne
#include <LiquidCrystal.h> // built in library
LiquidCrystal LCD(10, 9, 6, 5, 4, 3); //connection pins to LCD
// Variables seup here.
volatile long pauseTime = 5000000; // time between triggering and flash firing uS
volatile int timeoutFlag = 0; // set to 1 if trigger pushed and timeout not expired
const int led = LED_BUILTIN; // the pin with on-pcb LED Uno pin 13, Nano pin 16
const int triggerPin = 2; // user input to start pause Uno pin 2 Nano pin 5
const int flashpausePin = 12; // output to flashgun
const int coarsePausePot = A0; // user coarse input pot
const int finePausePot = A1; // user fine input pot
long int pause = 1023; // user input pot to set pauseTime
long int oldPause = 1023; // last reading from user input pot
long int coarsePause = 400000; // var to store user input
long int finePause = 100000; // var to store user input
int val; // misc variable
int ledState = LOW; // LED status (on or off)
int timeout = 1000;                   // timeout before sytem can trigger again mS
void setup() {    // put your setup code here, to run once: *************************
pinMode(led, OUTPUT); // set on-pcb LED pin as output
pinMode(triggerPin, INPUT_PULLUP); // user input pin to start pause
pinMode(coarsePausePot, INPUT); // user input pot to set coarse pauseTime
pinMode(finePausePot, INPUT); // user input pot to set fine pauseTime
pinMode(flashpausePin, OUTPUT); // setup flashpausePin - this will connect to flashgun
EIFR |= (1 << INTF0); // clear interrupt flags
Timer1.initialize(500000); // setup timer 500000uS
Timer1.stop(); // stop timer as not needed yet
Timer1.attachInterrupt(timer1Expired); // setup interrupt timer1Expired to run for pauseTime uS
attachInterrupt(digitalPinToInterrupt(triggerPin), trigger, FALLING); // setup interrupt
EIFR |= (1 << INTF0); // clear interrupt flags

Serial.begin(9600); // debug setup output to screen
LCD.begin(16, 2); // format of LCD 16 column by 2 rows
LCD.clear(); // clear LCD screen
LCD.setCursor(0, 0); // position cursor on LCD
LCD.print(" TriggerTimer "); // print to LCD
}

// ISR when triggered, sets Timer1 pauseTime
void trigger (void) {
if (timeoutFlag == 0) { // check timeout time has expired before allowing new trigger
Serial.print("push button: "); // debug
Serial.println(pauseTime); // debug
Timer1.setPeriod(pauseTime); // activate timer pause counter
digitalWrite(led, HIGH); // turn on led for duration of the pause
timeoutFlag = 1; // set timeout flag to stop second activation
}
}
// ISR is called at the end of Timer1 period.
void timer1Expired(void){
Serial.println("ISR called"); //debug print to screen
digitalWrite(flashpausePin, HIGH); // fire flashgun
digitalWrite(led, LOW); // turn off led
Timer1.stop(); // stop timer as no longer needed
}
// end of ISRs ***************************************************
void loop() { // put your main code here, to run repeatedly:**********************  
// read and format user input
coarsePause = analogRead(coarsePausePot); // readuser input from coarse pause pot
finePause = analogRead(finePausePot); // readuser input from coarse pause pot
coarsePause = map(coarsePause, 0 , 1023, 0, 5000); // map input
finePause = map(finePause, 0 , 1023, 0, 500); // map input
coarsePause = (coarsePause * 100); // multiply input to give uS
finePause = (finePause * 2); // multiply input to give uS
  pause = (coarsePause + finePause);                   // add coarse & fine delays to give total pause
  // Update Pausetime if user has changed input
if (pause != oldPause) { // if user changed pause, update
noInterrupts(); // turn off interrupts as variable is used in ISR
pauseTime = pause; // update var used in interrupt
interrupts(); // turn on interrupts
    oldPause = pause;                           // update to check next time round
    // update LCD
LCD.setCursor(6, 1); // position LCD cursor
LCD.print(" "); // blank out old reading
LCD.setCursor(6, 1); // position LCD cursor
LCD.print(pauseTime); // print updated pauseTime to LCD
  }
  val = digitalRead(flashpausePin);           // read flashpausePot
if (val == HIGH) { // if flash has fired...
Serial.println("Flash has Fired"); // debug
delay(100); // delay before releasing flash contacts
digitalWrite(flashpausePin, LOW); //.........and open contacts
delay(timeout); //.....timeout delay....
timeoutFlag = 0; //reset timeoutFlag
}
else { // debug
Serial.println("not fired"); // debug
delay(1000);
  }                                           // debug
  // debug print out variables to screen
Serial.println(finePause);
Serial.println(coarsePause);
  Serial.println(pause);
  Serial.print("pause time:    ");          // debug output to screen
Serial.println(pauseTime); // debug output to screen
Serial.println(" ");
  delay(500);
  // end of void loop **********************
}
 
Excellent work Sérgio!
Glad you have a working prototype.

They are good questions Sérgio, indeed the start button is supposed to start the sequence, but it should only do one cycle, and then wait until the button is pressed again to start another cycle.

This line of code is where the program waits.

C-like:
buttonSTATE=digitalRead(startBUTTON);
if(buttonSTATE==LOW) { //Wait for start button to be pressed before continuing
It shouldn't keep cycling, it should perform the solenoid and camera actions, then return to this inside the void loop and wait for the button to be pressed again.

I had some issues with the start button too, but because of my lack of electronics knowledge, I did some trial and error to get it to work.
I used a 1 KΩ resistor as a 'pull-up' resistor....I believe that's the right term!


Just reading through the older posts & noticed the above.
There are two issues, first, buttons should always have pullup or pulldown resisters, else the voltage floats & can cause all sorts of issues as the poor Arduino does not know what state (high or low) the button should be.
Luckily the answer is simple, the Arduino has built in pullup resisters, so there is no need to add external ones, just change the line in the code by adding '_PULLUP' as below. This will add a 10k pullup resister for you. Using a 1K resister is a bit low & is drawing 5mA

pinMode(triggerPin, INPUT_PULLUP);

The second is that switches are mechanical and don't just make or break once, but many times as we push or release them. They need to be debounced.
Just read the link below, Hardware debouncing is best, just a resister and a capacitor as shown in the first picture, better still use the IC in the second picture
https://hackaday.com/2015/12/09/embed-with-elliot-debounce-your-noisy-buttons-part-I/
 
Thanks Bill (@billbillbill ) for your work on the coding....it's invaluable!(y)
I've been reading quite a bit on interrupts lately, and it's been hard to adapt the general rules to something specific to drop controllers etc, so your code will certainly be a very useful learning tool.
Am I right in assuming that this would be better suited to a sound trigger system for example (eg. capturing an airgun pellet impact), rather than a water drop controller?
As we've discussed earlier, it seems that the interrupt function is better suited to much finer timings - in microseconds.
Not trying to avoid interrupts or anything, it's just that my brains are hurting!:giggle:

I've also moved to the I2C protocol for 20x4 LCDs to free up some pins on my Nanos....working well so far.
Thanks for the advice on the PULLUP/PULLDOWN feature - I'd heard of this recently and thought it was pretty clever, and you've just clarified it well!

I've just installed as many relevant libraries as I can today - TimerOne etc, so I have no more excuses, I have to put something together....and fear not Bill, all my switches will be debounced!;)
Actually, I do have one final question....I have a few 4x4 membrane panels (BITSBOX LINK) would all these need debouncing if I were to use them?
I don't have any firm plans for them yet, but they're dirt cheap, so I bought a few....I'm sure they'll come in handy for something.

Once again, thanks Bill.(y)
 
Hi Gareth and Bill,

Some really good stuff here - thank you both :) I have already built an aquarium LED light time switch when the original died and have a multi trigger flash-o-matic project in the pipeline :D

The stuff on Interrupts is interesting and has brought back some college memories. Time for a tinker I think (y)

PS - @GarethB - It's usual to debounce pretty much any mechanical switch as the contacts can appear to change state multiple times as they are pressed.
 
Hi Gareth and Bill,

Some really good stuff here - thank you both :) I have already built an aquarium LED light time switch when the original died and have a multi trigger flash-o-matic project in the pipeline :D

The stuff on Interrupts is interesting and has brought back some college memories. Time for a tinker I think (y)

PS - @GarethB - It's usual to debounce pretty much any mechanical switch as the contacts can appear to change state multiple times as they are pressed.

Thanks Lee, I do feel very fortunate that you're here to offer valuable advice. (y)
Great minds eh!....I'm beginning to plan a multi valve, multi drop system too....with menus possibly!
It's a very steep learning curve...and I do have a tendency to slide downwards!!

I didn't do computing unfortunately....just stuffy old physics!...so again I'm very grateful to you and Bill for sharing your expertise.

On the 4x4 membranes....so all 16 contacts need denouncing? Fair enough, looks like I'll be needing a bunch more of those 74HC14 chips then!....another bitsbox order incoming!!:LOL:
 
...On the 4x4 membranes....so all 16 contacts need denouncing? Fair enough, looks like I'll be needing a bunch more of those 74HC14 chips then!....another bitsbox order incoming!!:LOL:

Bitsbox could retire soon at the rate we're ordering :LOL:

I wonder if there is a clever way of 'debouncing' the array of switches using common returns or something to save a load of connections?
 
hi @everyone

Yep, no getting away from it, all mechanical switches need to be debounced. You can of course do it in software, there are libraries for this, but best practice is always hardware debounce.

Using interrupts rather than delay is also good practice. whilst the microcontroller is sitting in a delay, it cannot be getting on with other things. For a drip controller it is not to much of an issue as we will be poised waiting for the drip rather than wanting to change settings on the Arduinio mid drip cycle.

Here is my code below for a combined trigger timer & splash/drippy thing. The camera flash delay uses an interrupt and the drips are a blatant rip-off of Gareth's code :eek:)

Pressing the startbutton (pin 11) will cause the drips to start and the delay timer will take it's timing from this button & fire the flash
Pressing the trigger button (pin 18) will cause the delay timer to start & fire the flash, but not operate the drips.
This uses an interrupt, so can be triggered by external sensors and will immediately jump into delay timing.

A development of the code will allow the user to select either of the above, or a third option of timing of the flash for the drips from an outside source, e.g a break-beam which starts the delay timer when broken by a blob of water for example. This is how my current system works, using the hiviz triggertimer3 and the astrosplash.

A few changes to Gareth's code. A pullup added to the trigger pin, using less variables and the LCD is only updated if there is a change, this stops the flickering and dimming of the LCD.

It is written for the megaa2560 as the nano does not have enough IO. Even if rotary encoders were used instead of the pots, the nano only has two pin interrupts, so would struggle. It is possible to use rotary encoders without interrupts, or use a multiplexing IO chip to give the nano more IO, but it is a bit of a faff.

Code:
// ver 1.8 24 March 2019
// Mega2560 version
//Note the word 'pause' used as 'delay' is a function & could cause confusion
//Note TriggerPin must be debounced, else it plays havoc. - look at link below...
//https://hackaday.com/2015/12/09/embed-with-elliot-debounce-your-noisy-buttons-part-i/
#define DEBUG false  //set to true for debug output, false for no debug ouput
#define Serial if(DEBUG)Serial
#include <TimerOne.h> // https://github.com/PaulStoffregen/TimerOne
#include <Wire.h> // built in libray
#include <LiquidCrystal_I2C.h> // built in library
LiquidCrystal_I2C LCD(0x27, 20, 4); // set the LCD address to 0x27
// how to wre LCD    https://www.youtube.com/watch?v=ZtwFpFIS1_0
// trigger timer  Variables seup here.
volatile long pauseTime = 850000; // time between triggering and flash firing uS
volatile int timeoutFlag = 0; // set to 1 if trigger pushed and timeout not expired
const int led = LED_BUILTIN; // the pin with on-pcb LED Uno pin 13, Nano pin 16
const int triggerPin = 18; // user input to start pause (interrupt 5)
const int flashLed = 23; // output to flashLed, lights when flash fires
const int pauseLed = 22; // output to pauseLed, lights between triggering and firing
const int coarsePausePot = A8; // user input coarse pause pot
const int finePausePot = A9; // user input fine pause pot
const int timeoutPot = A10; // user input time between triggering and re-triggering
long int pause = 620; // user input pot to set pauseTime
long int oldPause = 620; // last reading from user input pot
long int coarsePause = 500; // var to store user input
long int finePause = 120; // var to store user input
int val; // misc variable
int ledState = LOW; // LED status (on or off)
int timeout = 100; // timeout before sytem can trigger again mS
int timeoutOld = 10;
// splash vars
const int solPin = 7; // assign pin 7 to solenoid
const int camPIN = 6; // assign pin 6 to camera
const int dropOnePot = A1; // assign pin A1 to potentiometer 1
const int dropTwoPot = A2; // assign pin A2 to potentiometer 2
const int dropThreePot = A3; // assign pin A3 to potentiometer 3
const int dropDelayOnePot = A4; // assign pin A4 to potentiometer 4
const int dropDelayTwoPot = A5; // assign pin A5 to potentiometer 5
const int startBUTTON = 11; // assign pin 11 to startBUTTON
const int intTriggerSel = 10; // assign pin 10 to trigger select
int solDelayOne; // declare solDelayOne variable
int solDelayTwo; // declare solDelayOne variable
int camDEL; // declare camDEL variable
int dropOne; // declare dropOne variable
int dropTwo; // declare dropTwo variable
int dropThree; // declare dropTwo variable
int dropOneOld; // declare dropOne variable
int dropTwoOld; // declare dropTwo variable
int dropThreeOld;                   // declare dropTwo variable
int solDelayOneOld;                 // declare solDelayOne variable
int solDelayTwoOld;
int buttonSTATE = HIGH;             // set buttonSTATE variable to HIGH
boolean internalTrigger = true;      // select if drop button also starts trigger timer
void setup() {    // put your setup code here, to run once: *************************
//trigger timer
pinMode(led, OUTPUT); // set on-pcb LED pin as output
pinMode(triggerPin, INPUT_PULLUP); // user input pin to start pause
pinMode(coarsePausePot, INPUT); // user input pot to set coarse pauseTime
pinMode(finePausePot, INPUT); // user input pot to set fine pauseTime
pinMode(timeoutPot, INPUT); // user input pot min time before next trigger allowed
pinMode(intTriggerSel, INPUT_PULLUP); // user input select how flash is fired when using drop
pinMode(flashLed, OUTPUT); // setup flashLed - lights when flash fires
pinMode(pauseLed, OUTPUT); // setup pauseLed - lights between triggering and flash firing
Timer1.initialize(500000); // setup timer 500000uS
Timer1.stop(); // stop timer as not needed yet
Timer1.attachInterrupt(timer1Expired); // setup interrupt timer1Expired to run for pauseTime uS
  attachInterrupt(digitalPinToInterrupt(triggerPin), trigger, FALLING); // setup interrupt
  // splash
pinMode(solPin, OUTPUT); // set solPin to output
pinMode(camPIN, OUTPUT); // set camPIN to output
pinMode(dropOnePot, INPUT); // set potentiometer 1 as input
pinMode(dropTwoPot, INPUT); // set potentiometer 2 as input
pinMode(dropThreePot, INPUT); // set potentiometer 3 as input
pinMode(dropDelayOnePot, INPUT); // set potentiometer 4 as input
  pinMode(startBUTTON, INPUT_PULLUP);  // set startBUTTON as input
  Serial.begin(9600);                  // debug setup output to screen
LCD.init();
LCD.backlight();
LCD.clear(); // clear LCD screen
LCD.setCursor(0, 0); // position cursor on LCD
  LCD.print("    TriggerTimer    ");   // print to LCD
  LCD.setCursor(0, 1);                 // reset the cursor position
LCD.print("FLPa"); // Flash Pause
LCD.setCursor(10, 1); // reset the cursor position
LCD.print("TO"); // TimeOut
LCD.setCursor(0, 2); // reset the cursor position
LCD.print("Drp"); // print the line "Drp" drop
LCD.setCursor(0, 3); // reset the cursor position
LCD.print("Pau"); // print the line "Pau" pause
}
// ISRs go here *************************
// ISR when triggered, sets Timer1 pauseTime
void trigger (void) {
if (timeoutFlag == 0) { // check timeout time has expired before allowing new trigger
Timer1.setPeriod(pauseTime); // activate timer pause counter
digitalWrite(pauseLed, HIGH);
timeoutFlag = 1; // set timeout flag to stop second activation
}
}
// ISR is called at end of Timer1 period.
void timer1Expired(void) {
digitalWrite(pauseLed, LOW); // update state of pasuselength LED
digitalWrite(flashLed, HIGH); // fire flashgun
Timer1.stop(); // stop timer as no longer needed
}
// end of ISRs ***************************************************

void loop() { // put your main code here, to run repeatedly:**********************
// read and format triggertimer user input
coarsePause = analogRead(coarsePausePot); // readuser input from coarse pause pot
finePause = analogRead(finePausePot); // readuser input from coarse pause pot
coarsePause = map(coarsePause, 0 , 1023, 1, 800); // map input to mS
finePause = map(finePause, 0 , 1023, 0, 50); // map input to mS
  pause = (coarsePause + finePause);                   // add coarse & fine delays to give total pause
  // triggertimer - Update Pausetime & LCD if user has changed input
if (pause != oldPause) { // if user changed pause, update
noInterrupts(); // turn off interrupts as variable is used in ISR
pauseTime = pause * 1000; // convert to uS and update var used in interrupt
interrupts(); // turn on interrupts
oldPause = pause; // update to check next time round
LCD.setCursor(5, 1); // position LCD cursor
LCD.print(" "); // blank out old reading
LCD.setCursor(5, 1); // position LCD cursor
LCD.print(pause); // print updated pauseTime to LCD
  }                                          // end if
  // triggertimer -  Update timeout & LCD if user has changed input
timeout = analogRead(timeoutPot); // read user input from timeOut pot
timeout = map(timeout, 0 , 1023, 0, 500); // map result
timeout = (timeout * 10); // convert to mS
if (timeout != timeoutOld) { // if user changed timeut, update
timeoutOld = timeout; // update to check next time round
LCD.setCursor(13, 1); // position LCD cursor
LCD.print(" "); // blank out old reading
LCD.setCursor(13, 1); // position LCD cursor
LCD.print(timeout); // print updated pauseTime to LCD
  }

// splash Update drop & delay times & LCD if user has changed input
dropOne = analogRead(dropOnePot); // read analogue value from potentiometer 1
dropOne = map(dropOne, 0, 1023, 10, 100); // use map to increase accuracy of pot
if (dropOne != dropOneOld) { // only update LCD if value has changed
dropOneOld = dropOne; // copy var to check for change in if-loop
LCD.setCursor(5, 2); // set cursor position as bottom left
LCD.print(" "); // print 3 spaces to keep LCD clean
LCD.setCursor(5, 2); // reset cursor position
LCD.print(dropOne); // print the calculated time value dropOneval
  }                                       // end if
  dropTwo = analogRead(dropTwoPot);         // read analogue value from potentiometer 2
dropTwo = map(dropTwo, 0, 1023, 9, 100); // use map to increase accuracy of pot
if (dropTwo == 9) dropTwo = 0; // if below 10, set to 0, no second drop
if (dropTwo != dropTwoOld) { // only update LCD if value has changed
    dropTwoOld = dropTwo;                   // copy var to check for change in if-loop
    LCD.setCursor(9, 2);                    // reset cursor position
LCD.print(" "); // print 3 spaces to keep LCD clean
LCD.setCursor(9, 2); // reset cursor position
LCD.print(dropTwo); // print the calculated time value dropTwoval
  }                                         // end if
  dropThree = analogRead(dropThreePot);        // read analogue value from potentiometer 2
dropThree = map(dropThree, 0, 1023, 9, 100); // use map to increase accuracy of pot
if (dropThree == 9) dropThree = 0;
if (dropThree != dropThreeOld) { // only update LCD if value has changed
dropThreeOld = dropThree; // copy var to check for change in if-loop
if (dropThree == 9) dropThree = 0; // if below 10, set to 0, no second drop
LCD.setCursor(13, 2); // reset cursor position
LCD.print(" "); // print 3 spaces to keep LCD clean
LCD.setCursor(13, 2); // reset cursor position
LCD.print(dropThree); // print the calculated time value dropTwoval
  }                                            // end if
  solDelayOne = analogRead(dropDelayOnePot);        // read analogue value from potentiometer 3
solDelayOne = map(solDelayOne, 0, 1023, 20, 200); // use map to increase accuracy of pot
if (solDelayOne != solDelayOneOld) { // only update LCD if value has changed
solDelayOneOld = solDelayOne; // copy var to check for change in if-loop
LCD.setCursor(5, 3); // set cursor position as bottom line, 9 characters from left
LCD.print(" "); // print 3 spaces to keep LCD clean
LCD.setCursor(5, 3); // reset cursor position
LCD.print(solDelayOne); // print the calculated time value dropThreeval
  }                                                 // end if
  solDelayTwo = analogRead(dropDelayTwoPot);        // read analogue value from potentiometer 3
solDelayTwo = map(solDelayTwo, 0, 1023, 20, 200); // use map to increase accuracy of pot
if (solDelayTwo != solDelayTwoOld) { // only update LCD if value has changed
solDelayTwoOld = solDelayTwo; // copy var to check for change in if-loop
LCD.setCursor(9, 3); // reset cursor position
LCD.print(" "); // print 3 spaces to keep LCD clean
LCD.setCursor(9, 3); // reset cursor position
LCD.print(solDelayTwo); // print the calculated time value dropThreeval
  }                                                 // end if
  // Test for user input. If drop button pressed, start drop sequence
buttonSTATE = digitalRead(startBUTTON); // test state of start button
  if ((buttonSTATE == LOW) && timeoutFlag == 0) {       // if pressed, start drop sequence
    Timer1.setPeriod(pauseTime);                    // activate timer pause counter for flash delay
digitalWrite(pauseLed, HIGH);
LCD.setCursor(17, 1);
LCD.blink();
    timeoutFlag = 1;
    digitalWrite(solPin, HIGH);                     // set solPin to HIGH - open the solenoid for first drop
delay(dropOne); // delay for time value dropOne - first drop size
    digitalWrite(solPin, LOW);                      // set solPin to LOW - close the solenoid
    if (dropTwo != 0) {                             //test if second drop reqired
delay(solDelayOne); //delay for time value solDelayOneval
digitalWrite(solPin, HIGH); //set solPin to HIGH - open solenoid for second drop
delay(dropTwo); //delay for time value dropTwo - second drop size
digitalWrite(solPin, LOW); //set solPin to LOW - close the solenoid
    }
    if (dropThree != 0) {                     //test if third drop reqired
delay(solDelayTwo); //delay for time value solDelayOneval
digitalWrite(solPin, HIGH); //set solPin to HIGH - open solenoid for third drop
delay(dropThree); //delay for time value dropThree - third drop size
digitalWrite(solPin, LOW); //set solPin to LOW - close the solenoid
}
}
val = digitalRead(flashLed); // read flashpause
if (val == HIGH) { // if flash has fired...
Serial.println("Flash has Fired"); // debug
delay(100); // delay before releasing flash contacts
digitalWrite(flashLed, LOW); //.........and open contacts
delay(timeout); //.....timeout delay....
timeoutFlag = 0; //reset timeoutFlag
LCD.setCursor(17, 1);
LCD.noBlink();
}
else { // debug
Serial.println("not fired"); // debug
  }                                           // debug
  // debug print out variables to screen
if (DEBUG) {
Serial.print("finePause: ");
Serial.println(finePause);
Serial.print("coarsePause: ");
Serial.println(coarsePause);
Serial.print("pause: ");
Serial.println(pause);
Serial.print("pauseTime: "); // debug output to screen
Serial.println(pauseTime); // debug output to screen
Serial.print("timeout: "); // debug output to screen
Serial.println(timeout); // debug output to screen
Serial.println(" ");
delay(500);
}
}
// end of void loop **********************
 
A couple of fotos, showing my Digital readout for the Hiviz Multitrigger3 and Astrosplash. An acrylic case & stand for the LCD was ordered from Ebay, unfortunately they sent a totally different part, so still need to box it up.
The four little resisters are a potential divider for the input, as the Multitrigger puts out about 8 volts on it's test socked & the Nano is max 5.5 V in.
Running off a USB lead at the moment, but as the Nano has an onboard regulator, will run it from the 12V supply from the Multitrigger when all boxed up.
It autodetects if both Multitrigger & Astrosplash or just one is connected and the display adjusts accordingly, foto shows it in Multitrigger only mode.

multitrigger2.JPG
 
This is the Binford 3000 splash-o-matic.
Three solenoids are hooked up, they can be moved horizontally to vary the splash & the whole arm slides up & down to vary drop height.
The flash delay is triggered by a photo-interrupter, which can be seen below the middle solenoid.

Just made up from some MDF off-cuts. The arm is a 19" rack grill panel which I had lying around.



Binford3000.JPG
 
Last edited:
This guide is fantastic. I’ve been following it all week, building the various parts, coding here, soldering there, waiting for a BitsBox delivery here, so first and foremost thank you for this amazing and in depth guide.
I’ve just got a quick question (although I’m sure there will be more) and I do apologise if it’s been answered and I’ve missed it in my skim reading. With the phono/ audio cables, I managed to salvage some from my junk box, with the phono it looks like one set of strands makes up the outter layer and a separate is used inside, is this what you used on the positive and negative on the solenoid? And the 3.5 audio has 3 small wires did you just pick 2 and connect them to the group and shutter that you found in the shutter cable?
Thanks again :)
 
Thanks Natt, glad you find it useful!
There's a lot of stuff to read here :giggle: I admit it kinda snowballed into quite a lengthy topic!

I promise that I shall definitely address your questions later this evening.

Welcome to Talk Photography too Natt, definitely looking forward to seeing some of your drop photography very soon!(y)
 
@nattsteer

Hi Natt.

Firstly the phono question.

....with the phono it looks like one set of strands makes up the outter layer and a separate is used inside, is this what you used on the positive and negative on the solenoid?

Yes, this is what I did.

With the DC solenoid, it doesn't matter which way round you connect them, since it just requires a current to flow in any direction for the solenoid to work.
I usually do try to keep consistency by having the centre connection as power, and the outer as ground.

However, if you are using a solenoid with an on board LED to show when the solenoid is activated, then you will need to pay attention to which way round you connect it.

If you are using the AirTac valves which I have used in this build, then here is the link to take you to the page which explains how I connected them.
I used trial and error to find out which way round to connect to light the LED.

The camera connector question is a little more complex.

And the 3.5 audio has 3 small wires did you just pick 2 and connect them to the group and shutter that you found in the shutter cable?

Essentially yes, this is what I did, with a few caveats:

My guide is based on a Canon camera that uses the N3 style shutter connector, and unfortunately I have no experience of other brands.
I elected to use 3.5mm mono jack connectors to simpilfy things.

This image shows the Canon N3 connector:

full


Here is a quick diagram I made which illustrates the pins of both types of Canon shutter release connectors:

full


Basically what is happening inside a shutter release cable button, is the focus and shutter connectors are simply being connected straight to GND/common, when the button is pressed.
What I did was essentially trial and error again, since in testing, there is minimal risk to the camera.

I bought a cheap Canon N3 compatible shutter release cable, snipped off the 'button' bit, which left me with three wires - I then connected it to the camera and touched the wires to each other to find which one fired the shutter.
Since I would be manually focusing, I didn't worry about the focus connector, which is why I only needed mono connectors.
The focus wire was snipped and isolated.

As with the solenoid connection, it doesn't really matter which way round these are connected when hooked up to the circuit, since what is happening is the circuit inside the opto-coupler is closed when it receives it's signal from the Arduino, so this grounds the shutter connection, which fires the shutter, whilst maintaining electrical isolation from the rest of the circuit....which is very important!!

Here are some pics of the 3.5mm mono jack sockets I used:
(Red circles show the connections used - they are mono, but confusingly they still have three tabs)

This is a 3.5mm mono socket, sourced from BitsBox - BITSBOX LINK
(This is the BitsBox link to the 3.5mm mono jack plug that I used - BITSBOX LINK)

full


....and here it is installed inside my drop controller:
(Again, red circles show which tabs I soldered - you'll also see some more trial and error efforts, namely a blob of solder on the incorrect tab!!:facepalm:)

full


Hope this helps, and good luck Natt!:)
 
Last edited:
Thank you for your quick and detailed reply, it’s been a really big help. While I’ve been waiting for parts to arrive (can I just take a second to give a shout out to Bits Box and how amazing they are, fixed price first class postage? Discount scale pricing? And a family business to boot. Normally I’d be way over paying at Maplin so thank you for turning me on to this company) I had been moving what I could from breadboard to enclosure, namely the LCD and potentiometers. It all worked perfectly when breadboarding but now it’s all soldered up it’s not working, I’m just getting a lit screen.

Chances are I’ve not soldered it very well somewhere, but it did make me wonder as no one ever taught me, I’ve just always assumed when it comes to the power and grounds - when you breadboard obviously you’ve got the rails and can connect as many times as you’ve got rails, however when you’re wiring that’s not the case so I have always soldered one wire on to however many I need.

I’ll post some pictures later today when I’ve made more progress, but I hasten to add I’m not quite the talented carpenter you are! Thanks again :)
 
Glad I could help Natt!

I can certainly sympathise regarding having a working prototype breadboarded, only to find nothing works when soldering the circuit!
I too have had no training, and what I tried to do was set up my stripboard like a breadboard, with a power rail and a ground rail.
I know that my circuit was a lot bigger than it needed to be, but having some space helped me to troubleshoot the soldering mistakes I made....which were plentiful!!:LOL:
I'm sure with a considered, logical approach, you'll find the problem, and be up and running in no time!

BitsBox are indeed very good, I'm not sure how much I've spent there (I dare not look!:giggle:) but they have always been reliable and very reasonably priced.
By the way, I have recently become aware of another great component supplier - Switch Electronics.
They are based in Hull, and they sell quite a few components that BitsBox don't have, so between the two suppliers, pretty much everything is covered....and they are also very reasonably priced.
Here is the link to their website:

https://www.switchelectronics.co.uk/

I've been buying quite a lot of stuff from them over the past few months, and have found them to be very good - plus they offer free delivery for orders over £25.
Although they show on their website that they accept PayPal, they have told me (a few months ago) that unfortunately there is some kind of glitch, and are unable to process PayPal payments, so I've been paying by debit card.
I'm not sure if they have rectified this issue, but I will probably contact them about it soon, because I would prefer PayPal for the extra protection.

Best of luck Natt!(y)
 
Last edited:
Hi Gareth
This is my first post and it is to :ty: for the most useful guide I have found :clap::clap:
I've been reading for days and I've decided to follow your lead
Still in very early stages maybe by the end of the week there will be something to share


Regards
Tony
 
Hi Gareth
This is my first post and it is to :ty: for the most useful guide I have found :clap::clap:
I've been reading for days and I've decided to follow your lead
Still in very early stages maybe by the end of the week there will be something to share


Regards
Tony

Hi Tony, and a very warm :welcome: to Talk Photography!

Thank you very much for the kind comment!:)
I'm so glad that you are finding it useful.
I created it because there didn't seem to be any guides that suited my needs, being a novice with electronics and Arduinos etc..
I had been searching the internet for a guide that was suitable for beginners/novices, but that was more than just a prototype, and while there are some very good ones, there didn't seem to be one that fitted.
The few that are prototype/breadboard based are very good, but I wanted to move past the this stage and create a half decent, complete unit, and the more advanced guides required a skill set that is way beyond me!!

Mine is still evolving as we speak, in fact....I'm learning about how to implement more valves into my system, and using a menu driven function so I won't have to have loads of screens and buttons/knobs etc.!
It's moving slowly, but I think I'm getting there!!

Keep us posted Tony, and I'm sure I'm not alone in looking forward to seeing some of your amazing water drop images very soon!

Best regards
Gareth.:)
 
Sorry I didn’t post images the other day, I had a, shall we say, incident, involving a drill - I did say I wasn’t quite the carpenter you are! I’m hoping to get my circuit onto to pieces of stripboard (see pictures) and a Arduino nano when funds allow so hopefully it will all go into a rather tiny little box. I haven’t got any wingnuts yet so the structure is a little flimsy at the moment, but it fits together, I’m going to gently sand it and paint it black so the reflections in the drops show as black lines/dots/smudges (I have got some metallic silver paint so may actually try that instead)

One other question I did have, it seems I’ve mixed up the connections and the solenoid has the mono 3.5mm jack and the camera cable has the phono, from what I’ve read tgis shouldn’t matter, it’s just about them having a connection, is that right? Or am I better off cutting the connections and swapping them over? Thanks again :ty:



86702A4C-0D38-451E-B41C-20E5C751BA74.jpeg 02489B0F-DC02-4CA9-8D58-5AE39F68F555.jpeg
20BE3037-BC8D-479C-A59E-677EC0FB18A6.jpeg
You may notice a groove in the wood next to solenoid, I was going to trail the wires tidily through it, but then I thought if I ever want to add more I’d probably have to move the wires. I may put them there anyway and think that’s a problem for future Natt :p
 
Wow! Great work Natt!:clap:
That clear case looks really slick!

Sorry to hear of your 'drill incident' , I hope you didn't hurt yourself badly!
I've had a few myself too.... I sliced my thumb open whilst making my wooden box....seems I'm not as good a carpenter as I thought!!:sorry:
I've burned myself on the soldering iron too, more times than I care to remember!!:facepalm:

Regarding your connection question: you're right, it doesn't really matter which connector you use.
When I thought about which ones to use, I knew I wanted them to be different, so as not to be able to connect my camera accidentally to the 12 volt solenoid socket by mistake!!:eek:

Your support structure looks excellent!(y)
Good idea to implement some kind of cable control....I might do that too.... it's likely to get a bit 'bird-nesty' with more valves!
A wise idea to paint it black also....I must admit I never gave reflections off the frame much thought when I was building mine....but I will now!
Future Natt will have all the solutions to our problems!;)
An Arduino time machine is the next project perhaps!!:D

Great work again Natt, looking forward to seeing some amazing drop collision images soon.

I'm currently fleshing out my next (belated) instalment, and I must give a shout out to @Leebert for inspiring me to pick up the reigns again.
His excellent guide on how to build a high speed piezo driven trigger system is a great read and can be found HERE.

Best of luck to you Natt, and keep us posted!(y)
 
Last edited:
Hi Gareth, me again :p

Thank you for your kind words. I’m doing the final soldering and woodwork today and hoping to take it for a test drive either tonight or tomorrow.

One (I almost said last but I don’t want to make that promise :p) the resistors you have for the contrast. I currently have a pot, but as you rightly mention, it’s a waste as once it’s set you never have to touch it again. On your diagram you have two resistors connecting to what is labelled as pin 3 (V0) does that mean to connect the resistors to a wire to the cable that is currently going to pin 3 or to run another wire to pin 3 on the Arduino? I’m a little lost so may not being explaining myself very well! I hope
You can understand what I’m trying to say. Thanks as always for indulging my many queries :)
 
Hi Natt.

I think what you're asking about is called a voltage divider.

You can think of the pot like a variable voltage divider, one side is connected to +5V and the other end to ground.
The middle connection is connected to pin 3 (V0) of the LCD.
By turning the pot, you are varying the resistance and thence the voltage that pin 3 sees.

If I recall correctly, I think the contrast voltage which worked for me was around +1V, so by using a voltage divider to 'divide' the voltage (a 5:1 ratio in this case), I used a 5KΩ and a 1KΩ as shown in the diagram below.

full


My method was to use trial and error (yet again! :giggle:) to replace the pot with a fixed pair of resistors to get the appropriate voltage for correct contrast.
I could have done it properly, by measuring the resistances of the pot at various settings, but where's the fun in that?!:D
You might want to try different resistors to see what works best for you.

It doesn't really matter what values of resistor you use, so long as they have the right ratio.
Eg. if you wanted say +2.5V (and your supply voltage is +5V) you could use two 1KΩ resistors, or two 5KΩ resistors etc., so that the voltage is 'divided' equally.

So in this case I chose a 5KΩ and a 1KΩ, but I could have chosen a 50KΩ and a 10KΩ....anything as long as the ratio is 5:1.

Of course you could always stick with the pot if you didn't want to go to the trouble.
When I did that part of the build, I didn't have any cheap, preset type pots, which I might have used instead....always nice to have something to fiddle with!!:giggle:

I'll be embarking on a (probably lengthy) waffle about a more improved way of connecting LCD screens.
It's called the I²C (or I2C) protocol, and it's a very efficient way to connect up your LCD using many fewer pins.
I've even figured out a way to use more than one LCD on a single Nano board....it's all very exciting!!

Best of Luck Natt, I'm always happy to answer any questions....providing they're easy!!:p

Stay tuned folks!:)

[**Edit**]

I just realised I could have answered your question in one sentence! Sorry for waffling on!:sorry:
Yes, the middle connection of the voltage divider goes straight to pin 3 (V0) of the LCD.
You shouldn't connect it to the Arduino, it is an independent control.
 
Last edited:
One other thing that could be tried is to use a 'pot' temporarily and set it to a point where the contrast is just right for you. Then, assuming that there is a multimeter handy, remove the pot from the circuit carefully without accidentally adjusting it and measure the resistance values between the middle terminal and one end, note it down and then repeat for the middle terminal and the other end. That will give you the exact values of the resistors in question.

However, you almost certainly won't be able to get those exact values so you need to get the closest ones that you can. Resistors are manufactured in 'preferred values' that cover an entire range or 'decade'. It initially appears complicated as to why they are available in the values that they are but it's quite simple really once the tolerance of the resistor is taken into account. It's typically standard for all resistors no matter where they come from and a similar system is in place for capacitors too.

Apologies, I'm not great at explaining things - Have a look HERE as the chart near the start of the page is quite good at showing what I am trying (poorly) to explain!

I hope that helps a bit too :) (y)
 
What confused me was “pin 3” I thought you meant pin 3 on the Arduino, but you meant the third pin of the LCD i.e. V0, hence why you wrote V0 and I’m just slow! I’m always happy to hear what you’ve got to say though so no apology needed! And thank you for the extra information Lee :)
:ty:
 
View media item 107021
(Sorry, couldn't avoid it :ROFLMAO:)

View media item 107022
I will be reusing a old prototype arduino-on-breadboard so... Cable mess alert!!!
An, obviously, easier way is using a a plain arduino board as you all, smarter people, are doing :cool:
If anybody feels curious, an easy step by step guide can be found HERE
Will post a nice and clean schematics when I learn how to draw one ;)

View media item 107023General view of the "Inator"

Instead of potenciometers I'm going the rotary encoders way. Using two of them (and could be done with only one) I can control the four parameters needed.
One encoder selects the parameter and the other increases or decreases the value.

View media item 107026One disadvantage is that they use 2 wires instead of 1 for the pot, but as we need less of then, we are good.

View media item 107027The LCD is as 16x2 I2C, easier to connect (planning to move to a 20x4 for a future version)

View media item 1070302 optocouplers will control the camera and the flash separately

View media item 107029
Usage is planned to be:
1-Select the drops parameters and delay
2-Press button

Then the Fot-o-Got-Inator will:
1-Turn lights off
2-Open camera shutter
3-Drop 1, wait, drop 2
4-Wait
5-Fire flash
6-Close camera shutter
7-Turn lights on


There is still a lot to do but it is begining to work.

Three Airtac valves and related components are somewhere over the rainbow ocean on its way from China
Woodwork is also in progress


Let's see how (and when) this ends


Regards
Tony
 
@Leebert That's a nice, clear explanation....nicer and clearer than mine!! :D Cheers mate!(y)

@nattsteer Indeed the pin labelling can be confusing....especially when an idiot like me is let loose on it!!:D
I'll try to keep my diagrams clearer from now on.

@Seron That's great work Tony!
Great minds think alike sir!!;)
I've just completed my prototype of my new design of water drop controller, and it incorporates a rotary encoder, two I²C 20x4 LCDs and I've also been playing around with some ATMega328P chips (just arrived yesterday) and the 'Arduino UNO on a breadboard' method too.
I like the idea of being able to tailor the micro-controller to suit the purpose.
Not sure if I will actually build my drop controller using one of these, or just stick with the NANO....probably the latter however....seems with decent quality clones out there, it isn't any cheaper to 'DIY' - it is fun though!:giggle:

There's some great ideas in your work Tony, I especially like the idea of using a relay module to control the lights in the room....that's very clever and something that appeals to me, since my biggest worry is working with liquids and electronics in my tiny 'studio' with the lights off.....and my inherent clumsiness!!:giggle:
My original idea was to work with the lights on, and use max sync shutter speed to eliminate the ambient light. I feel that this always restricted me in terms of having to work with shutter lag, and more complex timings involving flash trigger timings too.
Although I've recently invested in three more Yongnuo flashes, which have high speed sync features, so I'll have to see if they work out.

Using a relay to control a small lamp, however, seems like the perfect solution, and (with your permission) I shall definitely be stealing borrowing this idea!!:D
Are you using your relay to control a 12DVC lamp?

I'm very interested in seeing your code using two encoders, since I've only been able to work with one so far.
Are you using two interrupts - one for each encoder?
And are you using some kind of menu structure?

I've gone with the 'switch-case' menu structure, using a typical 5 button keypad (like a keypad shield - utilising one analog input) for menu navigation, and one rotary encoder/interrupt to change the time values etc.
It's quite clunky and definitely not pretty, and I'm sure coding experts will be horrified....but it works....sort of!:giggle:

Thanks to @Leebert @Seron & @nattsteer for contributing, I'm really looking forward to seeing how all our respective projects progress!
 
@Seron That's great work Tony!
Great minds think alike sir!!;)
Of course we do :clap::clap:

I've just completed my prototype of my new design of water drop controller, and it incorporates a rotary encoder, two I²C 20x4 LCDs
Wow, that sounds great !!

I've also been playing around with some ATMega328P chips (just arrived yesterday) and the 'Arduino UNO on a breadboard' method too.
I like the idea of being able to tailor the micro-controller to suit the purpose.
Not sure if I will actually build my drop controller using one of these, or just stick with the NANO....probably the latter however....seems with decent quality clones out there, it isn't any cheaper to 'DIY' - it is fun though!:giggle:
I designed an "special" temperature control a couple of years ago and didn't want my client to open it and... "Oh! its's an arduino, those are cheap so I'm noy paying a lot for it" :mad::mad:It wasn't fun then... but now we are not working :naughty:
It has been collecting dust since then and think it's time to get it back to life

Although I've recently invested in three more Yongnuo flashes, which have high speed sync features, so I'll have to see if they work out.
I think they won't :confused:
HSS lets you use the flash at speeds over 1/250 up to your camera's max shutter speed, maybe 1/8000. But that is your "freeze speed", too low for crazy moving droplets.
I may be wrong, however.

Using a relay to control a small lamp, however, seems like the perfect solution, and (with your permission) I shall definitely be stealing borrowing this idea!!:D
Are you using your relay to control a 12DVC lamp?
Happy you find this idea "borrowable"
I will be using this "LED stickers" placed somewhere on the wood frame. They are cheap and give a good light
View media item 107031
I'm very interested in seeing your code using two encoders, since I've only been able to work with one so far.
Are you using two interrupts - one for each encoder?
And are you using some kind of menu structure?

I've gone with the 'switch-case' menu structure, using a typical 5 button keypad (like a keypad shield - utilising one analog input) for menu navigation, and one rotary encoder/interrupt to change the time values etc.
It's quite clunky and definitely not pretty, and I'm sure coding experts will be horrified....but it works....sort of!:giggle:

:agree: Let's horrify those experts :D:D

C++:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ooPinChangeInt.h>
#include <AdaEncoder.h>
#include <avdweb_Switch.h>

#define I2C_ADDR    0x27
#define BARRA_LED      9
#define LEDE          13
#define PIN_GO         8

#define ENC_VAL_A 4
#define ENC_VAL_B 5
#define ENC_SEL_A 6
#define ENC_SEL_B 7

#define CABECERA    " Go1 Int Go2 Fls"

int8_t clicks=0;
char id=0;
int8_t Gota[] = {0, 0, 0, 0};                    // Initial values
const byte DispCol[] = {1, 5, 9, 13};    // Colums where values will be displayed on LCD
int8_t Sel=0;


LiquidCrystal_I2C        lcd(I2C_ADDR, 2, 1, 0, 4, 5, 6, 7);  // LCD
AdaEncoder encoder1 = AdaEncoder('S', ENC_SEL_A, ENC_SEL_B);  // "Select" encoder
AdaEncoder encoder2 = AdaEncoder('V', ENC_VAL_A, ENC_VAL_B);  // "Values" encoder
Switch ButtonGO = Switch(PIN_GO);                             // "Go" Button


void setup() {
  //pinMode(BARRA_LED, OUTPUT); // not used
  pinMode(LEDE, OUTPUT);        // A led

  lcd.begin (16,2);    // Init display
  lcd.setBacklightPin(3, POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.home ();
  lcd.print("Fot-o-Got-Inator");
  lcd.setCursor(0, 1);
  lcd.print("      v0.1      ");
  delay(2000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(CABECERA);          //Display header
     
  for (byte i=0; i<4; i++) {    //Display initial drop values
    lcd.setCursor(DispCol[i]-1, 1);
    lcd.print(Sel == i ? "*" : " ");
    lcd.print(getPadded(Gota[i]));
  }
  //Single press
  ButtonGO.setSingleClickCallback(&FunctionTEST, (void*)"o"); // Set function to test current values
  //Long press
  ButtonGO.setLongPressCallback(&FunctionGO, (void*)"o");     // Once we get the right values use this to take several shots
}

void loop() {
  AdaEncoder *thisEncoder=NULL;
  thisEncoder=AdaEncoder::genie();  // Call encoder Genie
  if (thisEncoder != NULL) {        // Something has moved
    id=thisEncoder->getID();        // This is the encoder that has moved
    clicks=thisEncoder->query();    // CW or CCW

    switch (id) {
      case 'S':               // "Select" encoder has moved
        Sel+=clicks;          // Update the "selected" parameter
        if(Sel<0) Sel=3;      // If moved to the left of the first then go to the last
        if(Sel>3) Sel=0;      // If moved to the right of the last then go to the first
        for (byte i=0; i<4; i++) {    // Put a "*" to show the selected value
          lcd.setCursor(DispCol[i]-1, 1);
          lcd.print(Sel == i ? "*" : " ");
        }
        break;
      case 'V':                             // "Value"  encoder has moved
        Gota[Sel]+=clicks;                  // Update value
        if(Gota[Sel]<0) Gota[Sel]=0;        // Not less than 0...
        if(Gota[Sel]>999) Gota[Sel]=999;    // ...nor greater than 999
        lcd.setCursor(DispCol[Sel], 1);     // Display value
        lcd.print(getPadded(Gota[Sel]));
      break;
    }
  }
  ButtonGO.poll();    // Look for button press
}

void FunctionTEST(void* oo) {  // Doing not much here ;)
  lcd.setCursor(0, 0);
  lcd.print("      TEST      ");
  delay(2000);
  lcd.setCursor(0, 0);
  lcd.print(CABECERA);
}

void FunctionGO(void* oo) {  // Doing not much here ;)
  lcd.setCursor(0, 0);
  lcd.print("     GOING      ");
  delay(2000);
  lcd.setCursor(0, 0);
  lcd.print(CABECERA);
  Luz.On();
}



String getPadded(int num) {
  char buff[4];
  char padded[5];

  //sprintf function will convert the long to a string
  sprintf(buff, "%.3u", num); // buff will be "01238"

  padded[0] = buff[0];
  padded[1] = buff[1];
  padded[2] = buff[2];
  padded[3] = buff[3];
  padded[4] = '\0'; // The terminating NULL

  return String(padded);
}

I am using https://github.com/GreyGnome/ooPinChangeInt and https://github.com/GreyGnome/AdaEncoder
They use PCINTs so INT0 and INT1 pins are still free waiting future use
One encoder is connected to pins 4 and 5 and the other to 6 and 7
https://github.com/avandalen/avdweb_Switch handles the button detecting normal and long presses and acting accordingly.

There is actually no menu structure.
First encoder cycles the "Sel" variable 0 to 3
Second one acts on the array "Gota[Sel]" to change Drop1, Delay, Drop2 and flash delay
This array will be passed to FunctionTEST and FunctionGO that will handle the real work
It's simple and seems to work fine

This is what I've got so far
Willing to get some time to go further


Regards
Tony
 
Last edited:
Sorry I didn’t post images the other day, I had a, shall we say, incident, involving a drill - I did say I wasn’t quite the carpenter you are! I’m hoping to get my circuit onto to pieces of stripboard (see pictures) and a Arduino nano when funds allow so hopefully it will all go into a rather tiny little box. I haven’t got any wingnuts yet so the structure is a little flimsy at the moment, but it fits together, I’m going to gently sand it and paint it black so the reflections in the drops show as black lines/dots/smudges (I have got some metallic silver paint so may actually try that instead)

One other question I did have, it seems I’ve mixed up the connections and the solenoid has the mono 3.5mm jack and the camera cable has the phono, from what I’ve read tgis shouldn’t matter, it’s just about them having a connection, is that right? Or am I better off cutting the connections and swapping them over? Thanks again :ty:



View attachment 253310
View attachment 253311
You may notice a groove in the wood next to solenoid, I was going to trail the wires tidily through it, but then I thought if I ever want to add more I’d probably have to move the wires. I may put them there anyway and think that’s a problem for future Natt :p
Hi Nat.
I'm sorry to read that the drill and you are not having a good time together. :(

I think It does no matter what kind of connector you use for anything. Just make sure to what arduino pin is that conector wired and use it in code.
Trying to take a picture with a solenoid of a drop comming out of your camera is probably a bad idea :LOL:

Really a good and compact box design
And the woodwork is amazing
Could you please provide more details about holding the valve to the structure?
Thanks in advance


Regards
Tony
 
I think It does no matter what kind of connector you use for anything. Just make sure to what arduino pin is that conector wired and use it in code.
Trying to take a picture with a solenoid of a drop comming out of your camera is probably a bad idea :LOL:
No, not the best idea!

Really a good and compact box design
And the woodwork is amazing
Could you please provide more details about holding the valve to the structure?
Thanks in advance
I’ll take some pictures for you later, but essentially I have a small block of wood with a long bolt through it, on the back of that I attached the solenoid (so it looks like the solenoid looks like it has the long bolt coming out it’s back).

Then I have a piece of wood with two little blocks either end, the solenoid goes through the middle of this piece with a wingnut. The two main support legs of the structure have equally spaced pairs of holes drilled along their length to push two long bolts through to the blocks and secured with wingnuts to allow for height adjustment.

Hopefully that makes sense, it’s very similar to Gareth’s frame which I stole borrowed the rough idea for :p
 
It was all going so well. Everything soldered. Pins crimped. But then I plug it in and, first of all I made the mistake of assuming my lcd would need the same resistors and not bother checking the value of the potentiometer I’d been using with my multimeter so I was presented with a row of black squares, but when I croc clipped a pot on this is what I was presented with:
2D0FD428-82F4-4A86-8F23-10F0A4DAF13C.jpeg
I don’t even know where to start troubleshooting :help::thinking: There’s obviously noise or or something corrupting the signal, maybe due to my lousy soldering, I’m not sure. The temptation is to throw it on the bonfire and start again. But as I know from being a coder for a fair few years now, the frustration only makes the eventual success all that much sweeter!
 
@nattsteer - that looks strange!

It obviously seems to power up ok, but the only thing I can think of is that there is indeed a signal issue....maybe a shorted pin or an accidentally swapped wire, perhaps due to a soldering issue.
I remember when I first powered mine up, nothing worked, and it was then the laborious process of troubleshooting - checking every single connection and track etc.
I found quite a few problems with mine, wires in the wrong place....tracks not broken properly etc....honestly I'm very surprised I didn't fry anything the first time I powered up!

Does anything happen to those jumbled characters when you turn the pots?
Are there any changes to the characters?

When you croc-clipped a pot, do you mean you connected one in parallel to the resistors that you have in place?
If so then this would certainly affect the display in some way I would think.
I think you should replace the incorrect resistors so that you are getting the right contrast, and start from there - at least you can then dismiss it as a potential problem.

Have you plugged in a camera and solenoid to test the functionality (albeit with arbitrarily chosen 'blind' values), and if so does it run the sketch correctly?
If so, this would definitely point towards an issue with the display only, which would narrow things down significantly.

It's possible it's a software/library issue, but I'm not convinced of this with your coding experience....just thought I'd mention it!

I know this is going to sound like a lot of faffing, but if you have a Flickr account, and uploaded some hi-res images of both sides of your board, and then link them here, I would be happy to scrutinise them for any errors....I know only too well how easy it is to become tunnel visioned and not see problems straight away....fresh eyes and all that!
I can't make any promises, but I'd be glad to help if this is something you would like to do.

I wish I could be more helpful....I'm sure you'll get it working soon....and don't throw it on the bonfire - if you put 12V into the +5V, it'll blow up all by itself!:p
I'm kidding....don't do this....I did, and all I got was a rather disappointing 'pop'!:D

Best of luck Natt, and don't give up mate!(y)
 
@Seron Thanks for posting your code Tony.(y)
It's certainly horrifying!!:eek:
I'm joking of course :D, it looks great....although I won't pretend to know how it works!:thinking:

Those libraries look very interesting however, especially the 'GrayGnome/ooPinChangeInt' one - I never knew you could add more interrupt pins to an Arduino....this could be very useful indeed, thanks for the links - duly bookmarked!

I think they won't :confused:
HSS lets you use the flash at speeds over 1/250 up to your camera's max shutter speed, maybe 1/8000. But that is your "freeze speed", too low for crazy moving droplets.
I may be wrong, however.

You're right about 1/8000th not being fast enough, but the way I would use them would be to set my shutter speed at say 1/1000th of a second (to be sure that I am eliminating all ambient light) and use my three flashes at lowest power (1/128th) thus retaining the very short flash duration of around 1/20000th of a second, which would be fast enough to freeze the drop.

But, now I'm thinking I like your idea of using a LED sticker better - programming it to turn off when the drop sequence starts and using bulb mode on the camera sounds a lot easier.
I'm having trouble finding those neat little LED stickers however....do you think a couple of ultra bright, white LEDs would work ok?
If they were placed inside a makeshift cone to give a more even spread....just might work, and the LEDs are only 32p each!
 
Back
Top