Send TTL from Arduino to Bonsai

1,641 views
Skip to first unread message

Victoria Corbit

unread,
Mar 18, 2018, 10:40:48 AM3/18/18
to Bonsai Users
Hello, I am fairly new to Arduino and extremely new to Bonsai, and I need to interface these to perform a fluorescence photometry experiment in mice. 

My Bonsai file acquires fluorescence imaging data but also synchronously captures behavioral video so that I can later time-lock my behavior to the fluorescent signal. I am also using an Arduino to control a water pump to deliver water drops to the mouse's head at random times. I would like to send a copy of the TTL waterdrop control signal to Bonsai so that I can have this signal synchronized with the behavior and fluorescence data.

As far as I understand I need to use the Firmata library, but I am having a lot of trouble figuring out which lines of code are needed to do what I want to do. For instance, it's not clear to me exactly what I need to initiate for Firmata to work, in the examples I've seen there are several loops other than the "setup" and "loop" that I am used to in Arduino.

I've tried to combine the "SimpleDigitalFirmata" example with my simple test code that cues a 900ms TTL pulse every 5s. However I'm not sure which parts of the example are necessary for what I want to do, because I only need to send TTLs to Bonsai, not receive them, and the example code isn't commented very well.

Here's my test code as well as a screenshot of my Bonsai file. The relevant part of the Bonsai file is the part at the bottom where it says "DigitalInput"... at least as far as I understand, everything else about my Bonsai file is irrelevant to this question. 


Thanks so much for any help, I have been banging my head against the wall trying to figure out how to do what seems like it should be really simple...



#include <Boards.h>
#include <Firmata.h>
#include <FirmataConstants.h>
#include <FirmataDefines.h>
#include <FirmataMarshaller.h>
#include <FirmataParser.h>

int testPin = 13;
byte sendPin = 13;
int pulsewidth = 900;
int trialN = 56;
int t = 0;
int portData = 1;

void outputPort(byte portNumber, byte portValue)
{
  // only send the data when it changes, otherwise you get too many messages!
  if (previousPIN[portNumber] != portValue) {
    Firmata.sendDigitalPort(portNumber, portValue);
    previousPIN[portNumber] = portValue;
  }
}

void setPinModeCallback(byte pin, int mode) {
  if (IS_PIN_DIGITAL(pin)) {
    pinMode(PIN_TO_DIGITAL(pin), mode);
  }
}

void digitalWriteCallback(byte port, int value)
{
  byte i;
  byte currentPinValue, previousPinValue;

  if (port < TOTAL_PORTS && value != previousPORT[port]) {
    for (i = 0; i < 8; i++) {
      currentPinValue = (byte) value & (1 << i);
      previousPinValue = previousPORT[port] & (1 << i);
      if (currentPinValue != previousPinValue) {
        digitalWrite(i + (port * 8), currentPinValue);
      }
    }
    previousPORT[port] = value;
  }
}

void setup() {
  // put your setup code here, to run once:

  pinMode(testPin, OUTPUT);
  Serial.begin(57600);
  Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);
  Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
  Firmata.attach(SET_PIN_MODE, setPinModeCallback);
  Firmata.begin(57600);
}

void loop() {
  for(int t=0; t < (trialN-1); ++t){

Serial.println(t);
//Turn on pulse
digitalWrite(testPin, HIGH);
Firmata.sendDigitalPort(sendPin, portData);
delay(pulsewidth);
digitalWrite(testPin, LOW);
delay(5000);

  }
}
BonsaiArduinoTestScreen.JPG

Gonçalo Lopes

unread,
Mar 18, 2018, 7:23:47 PM3/18/18
to Victoria Corbit, Bonsai Users
Hi Victoria and welcome to the forums!

The issue here is a confusion between "pin" and "port". In Arduino, all digital pins are grouped into blocks of 8 pins, called "ports". Each port is represented by a single byte (with 8-bits). In order to send digital state data from Arduino using Firmata, you have to send the whole port at the same time (i.e. you have to send the whole byte).

Your code is mostly correct, but this line is the problem:

Firmata.sendDigitalPort(sendPin, portData);

In this function, the first argument is not the pin, but the port. For example, the port where pin 13 is located is port 1 (in Arduino Uno). Also, the port data is not the state of the pin (LOW or HIGH), but actually the value of all pins in that port, combined into a single byte (where each bit represents the state of each pin).

Also, you need to call sendDigitalPort every time you change the pin, or else the computer won't know about it. Finally, you shouldn't call Serial.println() together with Firmata calls as this may confuse and break the protocol. The most minimalistic code to report a single pin state change using Firmata would be something like the following:


#include <Firmata.h>

byte testPin = 13;
byte testPort = 1; // the PORT for pin 13 is 1

void sendPortData(byte port)
{
    Firmata.sendDigitalPort(port, readPort(port, 0xff));

}

void setPinModeCallback(byte pin, int mode) {
  if (IS_PIN_DIGITAL(pin)) {
    pinMode(PIN_TO_DIGITAL(pin), mode);
  }
}

void setup()
{
  Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);

  Firmata.attach(SET_PIN_MODE, setPinModeCallback);
  Firmata.begin(57600);
}

void loop()
{
  digitalWrite(testPin, HIGH); // change pin to HIGH
  sendPortData(testPort); // send PORT data
  delay(1000);
  digitalWrite(testPin, LOW); // change pin to LOW
  sendPortData(testPort); // send PORT data
  delay(1000);
}



This should allow to change the state of the pin and send the updated PORT data to Bonsai.
Hope this helps, let me know if you would like me to clarify any point further.

--
You received this message because you are subscribed to the Google Groups "Bonsai Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users+unsubscribe@googlegroups.com.
Visit this group at https://groups.google.com/group/bonsai-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/bonsai-users/cb5901aa-e390-45ec-950e-849d9e499395%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Eirinn Mackay

unread,
Mar 20, 2018, 6:37:22 AM3/20/18
to Bonsai Users
Hi Victoria, you don't need to use Firmata to send an event to Bonsai. You can just send it via arduino's Serial.print command. For example you can send a "1", and then Bonsai's SerialStringRead source will fire and produce a "1".
Cheers,
Eirinn

Victoria Corbit

unread,
Mar 20, 2018, 2:55:40 PM3/20/18
to Bonsai Users
Wow, thank you so much for this! This helps a lot. 

I just want to clarify a couple things so I fully understand the code.
1) When you set up "sendPortData(byte port), are you essentially setting up a helper function to use later?
2) Why do I need the "setPinModeCallback" portion? Shouldn't sending the port data be enough?
3) I need to sendPortData for every time I want to either change a pin to high OR to low, correct?
4) I noticed that when I am actually sending data to Bonsai, it's only the port information I include, not the pin. Does that mean that I couldn't use multiple pins on Port 1 to send data at different times to Bonsai? Do I only get one pin to use per Port?

Thank you so much for your help again, this is infinitely more useful than anything else I've found on any other internet resources.
To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users...@googlegroups.com.

Victoria Corbit

unread,
Mar 20, 2018, 2:56:51 PM3/20/18
to Bonsai Users
Thanks Eirinn! I will try this, I had seen things online about using Serial but I wasn't sure if I could do that because I set up a lot of my arduino code to start running based on a key entry into Serial. So I wasn't sure if I could still use that and also use Serial to send data to Bonsai.

Eirinn Mackay

unread,
Mar 21, 2018, 6:58:01 AM3/21/18
to Bonsai Users
Yes only one program can connect to the serial port, so if you're currently relying on some software to send the serial command, Bonsai won't be able to connect because the port will be in use. Firmata also uses Serial so the same limitation applies.

Gonçalo Lopes

unread,
Mar 25, 2018, 4:21:21 PM3/25/18
to Victoria Corbit, Bonsai Users
Hi Victoria,

I just want to clarify a couple things so I fully understand the code.
1) When you set up "sendPortData(byte port), are you essentially setting up a helper function to use later?

Yes, that is correct, this is basically to avoid having to repeat reading the port state (with full bitmask) and sending it through Firmata for every single port.
 
2) Why do I need the "setPinModeCallback" portion? Shouldn't sending the port data be enough?

That may work. However, for good Arduino practice you should set the correct pinMode of digital pins (reading or writing), even if you are just reading. The setPinModeCallback function takes care of this, and Bonsai will send a message to set the pin mode during startup.
 
3) I need to sendPortData for every time I want to either change a pin to high OR to low, correct?

Well, technically you could change pins HIGH or LOW even without calling this, but then Bonsai would not know about the change in state.
 
4) I noticed that when I am actually sending data to Bonsai, it's only the port information I include, not the pin. Does that mean that I couldn't use multiple pins on Port 1 to send data at different times to Bonsai? Do I only get one pin to use per Port?

You can actually use multiple pins per port. The only limitation is that you always have to send the state of an entire port (i.e. in one byte). The state of each pin in that port is represented by different bits in the port byte coming up as HIGH or LOW. Bonsai understands this, so you can have different DigitalInput nodes pointing to different pins.
 
Thank you so much for your help again, this is infinitely more useful than anything else I've found on any other internet resources.

Thanks, glad it helped!


 
To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users+unsubscribe@googlegroups.com.

Victoria Corbit

unread,
Mar 30, 2018, 1:44:36 PM3/30/18
to Bonsai Users
Hi Gonzalo,

I'm having an issue with the program you wrote and I'm not sure if it's because of the Arduino or because I'm new to Bonsai. 

I have my test program in Bonsai set up (I think) to get the timestamps of the arduino inputs and write them to a CSV file. I start my arduino program first, then press play on Bonsai. Everything runs and the test.csv file is created. However, I can't stop the Bonsai program by pressing stop, and nothing is ever written to my CSV file. The only way I can get Bonsai to stop playing is if I close it. And when I do that, still nothing is written to my csv file.

Is this an issue with how I'm setting up the Arduino/Bonsai interface? 

Thanks and sorry for so many questions! Very new to Bonsai and arduino.


Hi Victoria,

Gonçalo Lopes

unread,
Apr 5, 2018, 6:12:53 PM4/5/18
to Victoria Corbit, Bonsai Users
Hi Victoria,

Sorry for the delayed response!
Can you attach the Bonsai workflow you are using, as well as the test Arduino program?

To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users+unsubscribe@googlegroups.com.

Victoria Corbit

unread,
Apr 6, 2018, 8:51:33 AM4/6/18
to Bonsai Users
Yes definitely! I've attached both.

I've been starting the Bonsai program first and then starting the Arduino program, because if I try to upload the Arduino program when Bonsai is already started, it says the Port is busy. But, once I start playing Bonsai, the only way to stop it is to close the program. 
Test.bonsai
BonsaiTest2.ino

Gonçalo Lopes

unread,
Apr 7, 2018, 4:59:26 AM4/7/18
to Victoria Corbit, Bonsai Users
Hi Victoria,

There seems to be no SerialPort specified in the DigitalInput node. This causes Bonsai to report an error message on my computer. Do you have the port specified on your side? If you don't and there is no error message, that would be a problem. Let me know if this happens. In any case, you need a valid serial port to connect correctly.

In my computer, your Arduino program and workflow combination works well. The file has data and I can open and close the connection multiple times.

There also seems to be a pin number mismatch: in the ".ino" file that you provided, the pin number is 12, but in the Bonsai DigitalInput node the pin number stated is 13. However, this still causes data to arrive since you are still sending the entire port, which should contain the state for all pins from 8-13.

This seems to be some low-level serial port configuration issue but it's unclear to me what could be causing it. Let me know if any of this helps.



To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users+unsubscribe@googlegroups.com.
Message has been deleted

Gonçalo Lopes

unread,
May 23, 2018, 7:48:20 PM5/23/18
to aaron....@gmail.com, Bonsai Users
Hi Aaron,

It is possible that the SAMD21 requires some kind of special serial port configuration, I don't think I have ever tried this specific model.
Can you try using SerialStringRead node to open a simple serial connection to the board and then try to close it? I wonder if that would work.

On 16 May 2018 at 20:12, <aaron....@gmail.com> wrote:
Hey,

I am also very new to Arduino and Bonsai and am trying to get my Arduino to communicate with Bonsai.

I have a SAMD21 arduino that is connected via USB to my computer. After downloading the Arduino IDE, I uploaded the Standard Firmata program onto my arduino. I then tried to read the analog output of the arduino to no avail. Similar to Victoria, I could no longer 'stop' my Bonsai Program by pressing the red square and had to close the entire program.

The exception Bonsai showed was the following: Unhandled Exception: System.ObjectDisposedException: Cannot access a disposed object.

I think the problem might have to do with the PIN. I am not sure which pin the USB port is, so i tried pins 0-15 but none of them worked. I also ensured the baudrate was the same for bonsai and arduino. I am not sure what to do next!

Thanks,
Aaron

--
You received this message because you are subscribed to the Google Groups "Bonsai Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users+unsubscribe@googlegroups.com.
Visit this group at https://groups.google.com/group/bonsai-users.

Nick Everett

unread,
Feb 5, 2019, 9:33:10 AM2/5/19
to Bonsai Users
Hi Victoria, 

I'm wondering if you've had success with integrating arduino inputs into bonsai, to add timestamps to the photometry data. I have a similar challenge, and am very new to all three things (photometry, bonsai, arduino).

Cheers,

Nick
Reply all
Reply to author
Forward
0 new messages