Hi, I'm working on a LED strobe meant to make water droplets appear to freeze in mid-air. It needs to run at about a 10% duty cycle with a frequency somewhere between 40 and 70Hz. (Getting the latter right is going to involve some trial and error, so I'm planning to include a pot for interactive adjustment.)
What I need help with is choosing the best coding method to use. I think the simplest is probably the best, but I would appreciate anyone's insight if I should pursue one of the other methods I've turned up. Right now, my goal is to get to a proof of concept with a single bright white LED for the strobe and a single pot for adjusting frequency. Future iterations may involve RGB LEDS cycling through colors and additional pots or sensors.
Here are the options I've dug up.
The simple approach: Bit-banging the LED on/off using delayMicroseconds(). But are there any issues with also having to read the pot and calculate the delays as part of the main loop?
I've read through a guide on PWM register manipulation. I think I could do this myself, though this would push the limit of my skills as I'm only an occasional Arduino user. On the other hand, I haven't seen many examples, so it may be harder than I think it would be.
I've seen a few references to using interrupts, but haven't yet delved into this option.
Hardware: Seeeduino 4.2 (ATmega 328P-MU) + random white LED from my components box.
Well, the minute you start talking about duty cycle it seems you already made your mind on using PWM. I would use a different approach (although someone will come and say I'm using PWM anyways).
In your loop() check if an LED event is due (turn LED ON or OFF). If it is, do that and compute the next event time. Just mark the LED as ON or OFF so you can tell what its state is (yes, this is a Finite State Machine)
After this, check your pot (I would use an encoder), and adjust the interval accordingly for the next loop cycle.
At 70Hz, there will be plenty of time left on each iteration for a lot more to do.
And make a note to yourself: avoid using delay() inside loop()
Here's a simple duty cycle test pgm for Nano that times in microseconds and works from keyboard. Set serial monitor line ending to Newline.
/*
Duty cycle test pgm for Nano, in serial monitor:
enter p then pulse time in microseconds or
c then cycle time in microseconds or both like,
p10000,c100000
*/
uint32_t timer,
cycleTime = 1000000, // default 1 second
pulseLen = 10000; // default 10 ms
const byte pulseOut = LED_BUILTIN;
void setup()
{
Serial.begin(115200); // set line ending to Newline
pinMode(pulseOut, OUTPUT);
timer = micros();
}
void loop()
{
byte inChar;
if (Serial.available() > 0)
{
inChar = Serial.read();
if (inChar == 'p')
{
pulseLen = Serial.parseInt();
Serial.print("Pulse length = ");
Serial.println(pulseLen);
}
else if (inChar == 'c') {
cycleTime = Serial.parseInt();
Serial.print("Cycle time = ");
Serial.println(cycleTime);
}
else if(inChar == '\n'){} // skips 1 second delay
}
if (micros() - timer > cycleTime)
timer += cycleTime;
digitalWrite(pulseOut,micros() - timer < pulseLen);
}
There are basically 3 elements to take care inside your loop:
-whether it is time to turn on the LED (preset time interval has gone by since the last time it was turned on), do it and record the current time
-else, whether it is time to turn off the LED (preset ON time has gone by since it was turned on )
-adjust the interval/frequency. Using @JCA34F example you would tether the fixture to a computer. Or, you can work with your pot, or a couple of buttons …and a display
If you want to see the effect then you need tio take human eyes into consideration. We have persistence of vision for example where 24 frames per second or faster blend together, frames over 40 millis apart won't seem frozen and PWM is frames 1 or 2 millis apart.
8 or fewer flashes per second can work but 4 or less will be better for a freeze in motion.
Cameras have faster eyes, there are solved catch a balloon popping old projects for Arduino out there and the drop of water on water effects.
See about using a led car headlight "bulb" to get it real bright!
I'm a great believer in the KISS approach.
Your pot is unlikely to change rapidly. If it does basically its faulty.
bit banging at less than 100Hz - even with a very short duty cycle - isnt going to challenge the arduino.
Nor is reading the ADC to read the pot value.
However you could alternatively just use a 555 timer IC and a few components. (I've done this, it works and runs from a PP3 battery)
To get bright short pulses from an LED you can use a high intensity LED and discharge a capacitor through it.
Yup, the flicker fusion threshold starts around 60Hz, and I'm deliberately not going under 40Hz because the strobing that can affect epileptics runs from about 6-30Hz.
Pulse frequency. Should be equal to the water drop frequency. Otherwise you can have aliasing. Syncing the events may prove tricky. It's part of the fun. In your case, my guess is that the frequency will be lower than 100Hz, which is well within the Arduino capability. I go as high as 240Hz to freeze fan blades @ 13440RPM. Still have to try with a mototool. The vision persistence has nothing to do here.
Pulse duration. This depends on the water drop speed. I don't expect it to be high, so you can get away with a long pulse, such as 5-10ms. (Always lower than the interval between pulses, of course). My pulse generator (I use to measure fan speed) uses 100 microseconds, but I have to darken the room. If I go higher than that the fan blades appear blurry because they rotate very fast.
Pulse intensity. The light intensity you need is contingent on the surrounding light. This is a trial-and-error process. And remember, if you use a high-current LED your Arduino output pin should control a transistor, not a LED directly. Although the voltage regulator in a Seeeduino can provide up to 500mA it is recommended to use a separate power supply. I use a 12V LED powered off a lab power supply.
My recommendation is to use the lowest possible combination of pulse duration and pulse intensity to prevent dazzling. You can house the LED in a short opaque tube (such as a straw wrapped with masking tape) so you are not looking at it continuously.
After having fun with the water drops you will move on to fans and motors. Have fun!
That's how eyes work. Dim a led at 60 Hz with short ON times. Does it appear to blink? Say 1666 us ON and 15000 us OFF?
The appearance of the turntable strobe depends on synchronization with shiny flat spots along one of a few bands of flat spots... should work the same leds, no?
compiled and tested, my eyes see a dimmed led.
const unsigned long wait[ 2 ] = { 15000, 1666 };
unsigned long startUs;
byte index = 1;
void setup() {
pinMode( 13, OUTPUT );
digitalWrite( 13, index );
startUs = micros();
}
void loop() {
if ( micros() - startUs >= wait[ index ] )
{
startUs += wait[ index ];
index = !index;
digitalWrite( 13, index );
}
}
More properly wait[] should be waitUs[] to match startUs.
And if I blink led13 with PWM and wave it fast in low light, I get a trail of dots. If i want solid trails, maybe a digital pot would be a better choice than pulsing the led.