problem using delay to create digital pulses of fixed duration

634 views
Skip to first unread message

John Ormond

unread,
May 20, 2022, 5:58:40 AM5/20/22
to Bonsai Users
Hi all - 
I'm trying to create digital pulses which I'm outputting using DigitalOutput(DAQmx). I want the pulses to be of fixed duration, ideally around 1 ms, but can live with anything significantly shorter than the period of my video stream (around 30 fps, so about 30 ms). I'm setting the digital output high, followed by a delay set to 0.001 sec (i.e. 1 ms), and then setting the output low. The problem is that the delay is coming out much longer, and is variable, anywhere from 15 to 30 ms. This causes a crash when the video stream triggers another pulse before the previous pulse has terminated. Does delay not work at sub-second resolution? Is there a better way of doing this? 
Thanks!
Jake
digitalPulses.bonsai
digitalPulses.png

John Ormond

unread,
May 20, 2022, 8:15:20 AM5/20/22
to Bonsai Users

To follow-up, if I remove the delay node from the above code, then the pulses are roughly 1 ms long, as I want them. Unfortunately, if I combine this with video acquisition (code attached), I start getting random long pulses (i.e. most pulses ~1ms duration, but some are 10-20ms long). 
videoAcquisition_withPulses.bonsai

brunocruz

unread,
May 20, 2022, 4:07:31 PM5/20/22
to Bonsai Users
Heya,

When you start working with such small delays some jitter is to be expected. I am actually surprised that most of your pulses are reliably at 1ms tbh (might it be because the max refresh rate of the NIDAQ is 1khz?). The fact that when you connect the camera you get 10-20ms pulses might not be surprising as you are sharing computer resources (e.g processing and communication) which might slow down the workflow but also the communication between the computer and the NIDAQ. When you are moving to such short delays it is usually better to "outsource" the timing of the event to a dedicated external device. I have used Arduino in the past that, upon receiving a given serial instruction, send a pin HIGH wait for x microseconds and send it LOW. This strategy tends to work more reliably.

Hope it helps,
Bruno

John Ormond

unread,
May 21, 2022, 4:47:56 AM5/21/22
to Bonsai Users
Hi Bruno, 
What you write makes sense, but I've had this exact set-up working perfectly in LabView. The reason I've switched to Bonsai is that my plan is to incorporate DLC for tracking. I think the Arduino is a good option if others are having success, though. I've also seen some posts suggesting that some users are using AnalogOutput rather than DigitalOutput to send a ttl; I assume the advantage is sending a single output, rather than the pair of outputs (high, then low) that I am now; unfortunately, the usb6000 I have now doesn't have analog outs, but I should be able to get my hands on something that does. I'm a little worried since I noticed video acquisition was occasionally dropping some frames when I was sending out the pulses, but I will make a new post if it persists once I try these other approaches. 
Thanks for your help!
Jake

brunocruz

unread,
May 22, 2022, 12:02:20 PM5/22/22
to Bonsai Users
Out of curiosity:

" What you write makes sense, but I've had this exact set-up working perfectly in LabView" 
I dont know much about labview vs their .net api but just so I understand, how do you program the pulse? do you send a HIGH and and LOW instruction ? do you send the duration of the pulse? something else?

" I've also seen some posts suggesting that some users are using AnalogOutput rather than DigitalOutput to send a ttl;"
I suspect this might work becase you sending the full pulse waveform so you shouldnt have jitter in the output.

Finally, something has occured to me, when you are reporting that most of your pulses are 1ms, these were measured with the osciloscope? or are you infering using the timestamp operator?

Cheers,
Bruno

jonathan...@gmail.com

unread,
May 22, 2022, 1:38:55 PM5/22/22
to Bonsai Users
If you are getting very precise (micro-second level) delays in labview, then they are being executed in hardware, not by the CPU like Bonsai does (the delay is being programmed into some thing deterministic like and FPGA, microcontroller, or some specialized circuit). Anything that needs to use the host computer to generate delays is going to be non-deterministic and crappy looking. 

The way Bonsai interacts with Arduino (when using the Bonsai.Arduino library) is the Frimata library. AFIAK this basically creates a local model of all the IO provided  by the Arduino along with a remote-procedure-call protocol that sends the commands from interactions with the model to the actual hardware. This is cool but is going to be terrible for real-time applications or applications where the phase of digital events needs to be precise because each pin manipulation results in a massive overhead involving the host CPU, USB communication, command-decoding and then finally microcontroller port manipulation.

An easy way to improve this situation is send a serial string to the arduino to trigger an event and the have the delay defined in a custom arduino script.

e.g.

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // None
}

// Turn LED on for 1 ms when any character is received
void serialEvent() {
    digitalWriteFast(LED_BUILTIN, HIGH);
    delay(1);
    digitalWriteFast(LED_BUILTIN, LOW);
    Serial.flush();
}


combined with the that attached bonsai workflow. I have not tested any of this but used a very similar approach in the past.
blink.ino
click-to-blink.bonsai

John Ormond

unread,
May 23, 2022, 4:48:36 AM5/23/22
to Bonsai Users
Hi Bruno, 
Pulses were recorded into the Intan recording software. I should clarify, I never actually measured the pulse duration, I could just see by eye that they were roughly the same duration, which was all I required. The problem I'm having in Bonsai is that I get very long pulses randomly generated which are on the order of the inter-frame period (i.e. ~30 ms). And to further clarify, I don't need the pusles to be as brief as 1 ms, even 10-20 ms duration is fine, it's when they get really long that I then get an error, as it seems the system is trying to both send the LOW instruction simultaneously with the HIGH instruction for the next pulse. 

John Ormond

unread,
May 23, 2022, 4:56:16 AM5/23/22
to Bonsai Users
" If you are getting very precise (micro-second level) delays in labview, then they are being executed in hardware, not by the CPU like Bonsai does"
Sorry, I way maybe not clear enough in my description. I don't require micro-second level precision, and don't imagine I was getting this in LabView. I'm using exactly the same NI box with Bonsai as I was with LabView (USB 6000, all timing CPU based afaik). If I could get sub-10ms level precision, I'd be happy enough. 

Thanks for the Arduino advice and workflow. Should have my Arduino in a day or two and will give that a shot. Will post back once I have it working (or not :)). 
Cheers
Jake

John Ormond

unread,
May 30, 2022, 10:38:50 AM5/30/22
to Bonsai Users
I've got your code working after a couple of modification, so just wanted to say thank you and post up the modified code in case anyone else finds it useful. So just to recap, this code tells the arduino to output a digital pulse (in this case, 2ms long) every time the mouse button is clicked. 

A couple of things to mention about the arduino code: 1) you had Serial.flush() at the end of the pulse to presumably clear the serial buffer, but apparently it doesn't do this; once I clicked the mouse, I got a continuous stream of pulses. Serial.flush() was changed to Serial.read(), which did the trick. 2) digitalWriteFast isn't included in the standard arduino library but can be downloaded on github; just follow the instructions there (place it in your libraries folder, rename the folder from "digitalWriteFast-Master" to "digitalWriteFast", and import it within the arduino code (#include <digitalWriteFast.h>). Bear in mind I'm a complete novice with Arduino, so there may be other ways of achieving the same end result.

For the Bonsai code, String was set to "go". This actually resulted in 3 pulses concatenated together, one for the g, one for o, and I guess one for newline or something similar. Just leaving string completely empty worked for me. 
Thanks again!
Jake



On Sunday, May 22, 2022 at 6:38:55 PM UTC+1 jonathan...@gmail.com wrote:
blink_working.ino
click-to-blink.bonsai
Reply all
Reply to author
Forward
0 new messages