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

Messages
11
Name
bill
Edit My Images
No
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:)
 
OP
OP
GarethB
Messages
889
Name
Gareth
Edit My Images
Yes
@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!!!;)
 
Messages
11
Name
bill
Edit My Images
No
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);
}
 
Messages
11
Name
bill
Edit My Images
No
...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.

Code:
// This is just a demo, it is not a fully functioning piece of code.
// Note the word 'pause' used as 'delay' is a function & could cause confusion
// Note TriggerPin must be debounced, else it plays havoc.
// Follow the link below & use circuit shown after 'FIX IT IN HARDWARE'
// note 10K resister shown, is not needed as Ardiuno already has that built in.
// https://hackaday.com/2015/12/09/embed-with-elliot-debounce-your-noisy-buttons-part-i/
// For best results use circuit shown in next picure with 74HC14 IC (both 10k resisters required)
#include <TimerOne.h>
const int led = LED_BUILTIN;           // the pin with a LED
int ledState = LOW; // toggle state of LED
volatile unsigned long blinkCount = 0; // use volatile for shared variables in ISR
volatile long pauseTime=500000; // time between triggering and flash firing uS
const int coarsePausePot = A0; // user coarse input pot
unsigned long coarsePause = 400000; // time of pause
unsigned long blinkCopy = 0; // holds a copy of the blinkCount
const int flashpausePin = 12; // output to flashgun
volatile int timeoutFlag=0; // set to 1 if trigger pushed and timeout not expired
const int triggerPin = 2; // user input to start pause Uno pin 2
int val;                               // general use
void setup(void)
{
pinMode(led, OUTPUT); // built in LED
pinMode(triggerPin, INPUT_PULLUP); // user input pin to start pause
pinMode(coarsePausePot, INPUT); // user input pot to set coarse pauseTime
pinMode(flashpausePin, OUTPUT); // setup flashpausePin - this will connect to flashgun
Timer1.initialize(500000); // load timer with 0.5 seconds. Set this to the Max needed
Timer1.stop(); // stop timer as not needed yet
Timer1.attachInterrupt(blinkLED); // setup interrupt blinkLED
attachInterrupt(digitalPinToInterrupt(triggerPin), trigger, FALLING); // setup interrupt
Serial.begin(9600); //setup output to monitor
}

//Interrupt SubRoutines (ISR) go here
void trigger (void)
{
if (timeoutFlag == 0) { //check timeout time has expired before allowing new trigger
Serial.print("push button: "); // debug - not good practice to print inside ISR
Serial.println(pauseTime); // debug- not good practice to print inside ISR

Timer1.setPeriod(pauseTime); //activate timer pause
timeoutFlag=1; } // set timeout flag to stop second activation
} // end of trigger ISR
void blinkLED(void)
{
if (ledState == LOW) {
ledState = HIGH;
blinkCount = blinkCount + 1; // increase when LED turns on
} else {
ledState = LOW;
digitalWrite(flashpausePin, HIGH); //fire flashgun
Timer1.stop(); //stop timer as no longer needed
}
digitalWrite(led, ledState);
} // end of blinkLED ISR
// end of Interrupt SubRoutines (ISR)

// The main program will print the blink count
// to the Arduino Serial Monitor
// built in LED will light for length of pausetime
void loop(void)
{
coarsePause = analogRead(coarsePausePot); // read user input
coarsePause = map(coarsePause, 0 , 1023, 100000, 500000); // map input to uS

noInterrupts(); // turn off interrupts as variable is used in ISR
pauseTime = coarsePause; // update var used in interrupt
blinkCopy = blinkCount; // copy var used in ISR
interrupts(); // turn on interrupts

val = digitalRead(flashpausePin); // read flashpausePin -ISR turns this on after delay time
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(500); // delay before allowing next trigger
timeoutFlag=0; // reset timeoutFlag
}
else { // debug
Serial.println("not fired"); // debug
  }                                         // debug
// debug print out variables to screen
Serial.print("pause time: "); // debug output to screen
    Serial.println(pauseTime);                // debug output to screen
    Serial.print("blinkCount = ");            // debug output to screen
Serial.println(blinkCopy); // debug output to screen
Serial.println(" "); // debug output to screen
delay(500); // delay before allowing next trigger
}
 
Messages
11
Name
bill
Edit My Images
No
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:)
 
OP
OP
GarethB
Messages
889
Name
Gareth
Edit My Images
Yes
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.
 
Messages
11
Name
bill
Edit My Images
No
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.
 
Top