09e88e6feb
Added Ganglion Data Format, Clarified GUI page. Fixed broken links
113 linhas
7.2 KiB
Markdown
113 linhas
7.2 KiB
Markdown
#External Trigger on OpenBCI 8bit Board
|
|
Sometimes, when studying EEG or other biopotential signals, you will want to have precise timing between external events or stimulus and the data stream. For example, if you are working with P300 waves it is necessary to know the exact time that the signal was presented to the subject in order to look for the tell-tale wave that happens about 300mS after the stimulus.
|
|
|
|
This tutorial will cover a couple of ways to add an external trigger to the OpenBCI data stream on our 8bit Board. Please read this entire page before jaunting off into hardware hacking.
|
|
|
|
##External Triggering With A Button
|
|
The OpenBCI 8bit Board comes with an ATmega32 with Arduino UNO bootloader. It programs with the Arduino IDE [download here](http://arduino.cc/en/Main/Software). The code that is running on your 8bit board is located [here](https://github.com/OpenBCI/OpenBCI_8bit). In this example, we will lash up a pushbutton switch as an external trigger. Here's what you will need:
|
|
|
|
* OpenBCI 8bit Board with Female Headers
|
|
* Pushbutton Switch
|
|
* 10K Resistor
|
|
* Breadboard and Jumper Wires
|
|
|
|
###Step One
|
|
|
|

|
|
|
|
First thing to do is solder the female headers. Your OpenBCI 8bit board came with a selection of female header rows. Find the 8, 6, and 4 pin female headers, and solder them in to the top of the board. For this tutorial, we will access the GND on the 8 pin header row (left side). 5V and the input pins are located on the two headers on the right.
|
|
|
|
**Note** The 4 and 6 pin headers on the right are operating at 5V, and the 8 pin header on the left is operating at 3.3V. DO NOT CONNECT THESE PINS TOGETHER OR YOU RISK DAMAGING YOUR BOARD!
|
|
|
|
We have broken out the following Arduino pins:
|
|
|
|
|
|
| Pin Name | Default | Digital IO | Also Known As |
|
|
| ------- | ----- | ----- | ---- |
|
|
| A0 | Analog Input | Yes | 14 |
|
|
| A1 | Analog Input | Yes | 15 |
|
|
| A2 | Analog Input | Yes | 16 |
|
|
| A3 | Analog Input | Yes | 17 |
|
|
| A4 | Analog Input | Yes | 18 |
|
|
| A5 | Analog Input | Yes | 19 |
|
|
| A6 | Analog Input | No | not applicable |
|
|
| A7 | Analog Input | No | not applicable |
|
|
|
|
All of these pins default to Analog inputs. For this tutorial, we will be using a Digital input, connecting it to a pushbutton switch, and reading the input. First, let's initialize some variables. Note that I'm making an alias called buttonPin for pin A0, and I could have called it 14 just as easily.
|
|
|
|
int pushButton = A0;
|
|
int pushButtonValue;
|
|
int lastPushButtonValue;
|
|
|
|
void setup(){
|
|
// do stuff....
|
|
pinMode(pushButton,INPUT);
|
|
pushButtonValue = 0;
|
|
lastPushButtonValue = 0;
|
|
// do other stuff...
|
|
}
|
|
|
|
Then, in the loop, we wan to check for the rising edge of the button press, make note of it in the auxData[0] variable, and set the flag. Finally, we want to get the button press event into the data stream. (Reference the [OpenBCI Data Format Doc](http://docs.openbci.com/Hardware/03-Cyton_Data_Format) for data packet anatomy) There are 6 aux bytes available in each data packet, and the default format is to read them as three 16bit integers. By default, the accelerometer values are included in the data stream, and they update every 5th data packet (Accelerometer runs at 50Hz by default). When the OBCI.useAux boolean is set, the updated auxData value will get automatically written with the next data packet and override the accelerometer data if it's there. The overridden accelerometer data gets bumped to the next packet. Our sample rate of 250SPS gives us a 4mS resolution on external trigger events like the rising edge of a pushbutton press. In the example code, we are setting all three Aux values to 0x6220 (that's 25120 in decimal). This number gets converted to Gs by our Processing GUI, which thinks that it is accelerometer data. The resulting value is pi (3.14) which is easy to locate in the data stream.
|
|
|
|
pushButtonValue = digitalRead(pushButton); // feel the pushbutton
|
|
if (pushButtonValue != lastPushButtonValue){ // if it's changed,
|
|
if (pushButtonValue == HIGH){ // if it's gone from LOW to HIGH
|
|
// 0x6220 gets converted to 3.14 in Processing
|
|
OBCI.auxData[0] = OBCI.auxData[1] = OBCI.auxData[2] = 0x6220;
|
|
OBCI.useAux = true; // set the OBCI.auxData flag
|
|
}
|
|
lastPushButtonValue = pushButtonValue; // keep track of the changes
|
|
}
|
|
|
|
|
|
Here's what the sample string looks like in saved data file
|
|
41, -27.58, -29.30, -22.82, -28.54, -22.22, -20.52, -26.64, -12.32, 3.14, 3.14, 3.14
|
|
|
|
Here's a link to the github branch that implements this pushbutton input!
|
|
[OpenBCI Pushbutton Trigger](https://github.com/OpenBCI/OpenBCI_8bit/tree/OpenBCI_8bit_PushButton)
|
|
|
|
##External Triggering The Harder Way
|
|
Sometimes a situation may arise where you need to interface OpenBCI witn an existing system, for example an audio or visual event-related potential (ERP) that is being generated by an external system. In such a case, it is most desireable to have the onset of the signal tightly bound, temporally, with the EEG data. In such a case it is possible to interface OpenBCI with the signal generating system with a few low-cost interface parts.
|
|
Our goal with the OpenBCI board is to make biosensing safe and fun. The biggest part of the safety part is making sure that you can't plug yourself accidentally into the mains electrical supply (yikes!). If you are interfacing an external trigger that is **NOT** operating under a battery supply, we recommend thinking twice about incorporating it into your system/protocol. If you've thought twice, here's how we do it when we need to.
|
|
|
|
###Optoisolation
|
|
|
|
|
|

|
|

|
|
|
|
|
|
The simplest trick is to isolate the OpenBCI circuit from the trigger signal generating circuit. For this purpose, we picked an Optoisolator with 5000 Volts isolation between the input and the output. [CNY17](http://www.mouser.ee/ProductDetail/Vishay-Semiconductors/CNY17F-2X006/?qs=sGAEpiMZZMteimceiIVCB7Uit3aMEvQQFLjPtOr%2f870%3d) family from Vishay is a great example of a low-cost high islolation optoisolator. In the circuit to the right, when an external trigger of 3.3V to 5V is applied to the Anode of the input (pin 1), the output (pin 5) will go from HIGH to LOW.
|
|
|
|
|
|
int triggerPin = A0; // the CNY17 Collector is on pin A0
|
|
int triggerValue; // used to hold the latest trigger reading
|
|
int lastTriggerValue; // used to remember the latest trigger state
|
|
|
|
|
|
The code to read this trigger input is quite similar to the previous button code. In this case, we need to watch for the **falling** edge of the trigger.
|
|
|
|
|
|
void setup(){
|
|
// stuff here...
|
|
pinMode(triggerPin, INPUT); // set the button pin direction
|
|
triggerValue = lastTriggerValue = digitalRead(triggerPin); // seed
|
|
// more stuff...
|
|
}
|
|
|
|
void loop(){
|
|
// do stuff
|
|
|
|
triggerValue = digitalRead(triggerPin); // feel the trigger pin
|
|
if (triggerValue != lastTriggerValue){ // if it's changed,
|
|
if (pushButtonValue == LOW){ // if it's gone from HIGH to LOW
|
|
// 0x6220 gets converted to 3.14 in Processing
|
|
OBCI.auxData[0] = OBCI.auxData[1] = OBCI.auxData[2] = 0x6220;
|
|
OBCI.useAux = true; // set the OBCI.auxData flag
|
|
}
|
|
lastTriggerValue = triggerValue; // keep track of the changes
|
|
}
|
|
|
|
// do other stuff
|
|
}
|