const mind = require('wits')
mind.open()
mind.read(console.log)
wits lets you monitor your brain activity. It is an interface to Emotiv EPOC headsets, and reflects what goes on in your mind.
- Implemented as a native C module for raw performance (based on openyou/emokit-c)
- Raw EEG data stream of 14 electrodes with 128Hz sample rate
- Easy-to-use, humanized API
This project depends on external libraries like hidapi and mcrypt for USB communication. If you have both hidapi and mcrypt, you can skip this step.
Install external dependencies:
brew install hidapi mcrypt
Install via npm:
npm install wits
Here's a small example where we open a connection to an Emotiv EPOC headset and start reading the value of the AF3 electrode. The example pauses the data flow after 3 seconds, resumes it and finally closes the connection.
const mind = require('wits');
// Open your mind — the connection to the headset. This will quit after 10 retries.
mind.open();
// Start polling for data. The callback function will be called 128 times a second, so make sure it's performant.
mind.read(data => {
console.log(data.levels.AF3);
});
// Pause your mind �� data stream after 3 seconds. This stops the callback.
setTimeout(() => mind.pause(), 3000)
// Resume your mind — data stream after 5 seconds. This resumes the callback.
setTimeout(() => mind.resume(), 5000)
// Close your mind. This disconnects from the headset.
setTimeout(() => mind.close(), 9000)
Exposed by require('wits')
. A singleton that has open
, close
, read
, pause
and resume
methods to interact with Emotiv EPOC headset.
Looks for an Emotiv EPOC USB device and tries to connect to the headset. Retries the connection 10 times and returns if a successful connection could be made. This is a blocking call.
boolean
True if the connection is succesful
Sets a callback function to receive data from the headset represented as a Reading
type. This function will be called approx. 128 times a second with an object representing the electrode values. Must be called after a mind.open()
.
wits
holds a single callback in memory. Subsequent calls to mind.read
will replace the callback function and the previous handlers will stop receiving data. In other words, only the latest callback will receive new data packets.
callback
function(
Reading
)
A handler function that will receive an object confirming to type Reading
. This callback will continue to receive data packets until mind.pause()
or mind.close()
is executed.
Pauses the actively running incoming data stream. Useful to reduce CPU load when not in use. Must be called after a mind.read()
.
Resumes the incoming data stream. Must be called after a mind.pause()
.
Disconnects from the headset, stopping the data flow. Must be called after a mind.open().
Sets a function to receive logs from the headset. By default all the logs will be output to the stdout/stderr. However in certain scenarios users may want to redirect these logs to another stream. This method gives one the ability to specify a function that will receive any logs coming from the library, so the user chooses where and how to display the logs.
logger
function(string)
A handler function that will receive a single string parameter. Every time the library wants to log something, this function will receive it.
Example:
mind.setLogger(log => console.log(`[wits] ${log}`));
mind.open() // now all the logs will stream to the console and will include a `[wits]` tag at the beginning.
Object representing data values streamed from the headset. Passed as the first parameter to the callback provided within the mind.read
call.
Example:
{
"battery": 12,
"counter": 128,
"levels": {
"F3": 7705,
"FC6": 7766,
"P7": 8192,
"T8": 8514,
"F7": 8126,
"F8": 8362,
"T7": 7953,
"P8": 8558,
"AF4": 8127,
"F4": 9271,
"AF3": 7949,
"O2": 8239,
"O1": 7705,
"FC5": 8899
},
"cq": {
"F3": 16,
"FC6": 8,
"P7": 0,
"T8": 0,
"F7": 8,
"F8": 0,
"T7": 16,
"P8": 16,
"AF4": 24,
"F4": 16,
"AF3": 16,
"O2": 8,
"O1": 24,
"FC5": 16
},
"gyro": {
"x": 0,
"y": -1
}
}
Battery percentage between 0-100.
A 7-bit unsigned integer that's automatically incremented in each sample. Useful to track if there are lost packets.
levels → Levels
An object that has 14 electrode names as keys and 14-bit unsigned integers for each electrode. The values represent the amplitude of the signal which is about 8.4mV peak-to-peak. The smallest unit (represented by 1 bit) is 0.51µV.
cq → ContactQuality
An object that has 14 electrode names as keys and certain integers for each electrode.
gyro → Gyro
An object with x
and y
values that represent left/right and up/down rotation of the head.
An object that has 14 electrode names as keys and 14-bit unsigned integers for each electrode. The values represent the amplitude of the signal which is about 8.4mV peak-to-peak. The smallest unit (represented by 1 bit) is 0.51µV.
A 14-bit unsigned integer that represents the value of the F3 electrode
A 14-bit unsigned integer that represents the value of the FC6 electrode
A 14-bit unsigned integer that represents the value of the P7 electrode
A 14-bit unsigned integer that represents the value of the T8 electrode
A 14-bit unsigned integer that represents the value of the F7 electrode
A 14-bit unsigned integer that represents the value of the F8 electrode
A 14-bit unsigned integer that represents the value of the T7 electrode
A 14-bit unsigned integer that represents the value of the P8 electrode
A 14-bit unsigned integer that represents the value of the AF4 electrode
A 14-bit unsigned integer that represents the value of the F4 electrode
A 14-bit unsigned integer that represents the value of the AF3 electrode
A 14-bit unsigned integer that represents the value of the O2 electrode
A 14-bit unsigned integer that represents the value of the O1 electrode
An object that has 14 electrode names as keys and certain integers for each electrode.
A 14-bit unsigned integer that represents the contact quality of the F3 electrode
A 14-bit unsigned integer that represents the contact quality of the FC6 electrode
A 14-bit unsigned integer that represents the contact quality of the P7 electrode
A 14-bit unsigned integer that represents the contact quality of the T8 electrode
A 14-bit unsigned integer that represents the contact quality of the F7 electrode
A 14-bit unsigned integer that represents the contact quality of the F8 electrode
A 14-bit unsigned integer that represents the contact quality of the T7 electrode
A 14-bit unsigned integer that represents the contact quality of the P8 electrode
A 14-bit unsigned integer that represents the contact quality of the AF4 electrode
A 14-bit unsigned integer that represents the contact quality of the F4 electrode
A 14-bit unsigned integer that represents the contact quality of the AF3 electrode
A 14-bit unsigned integer that represents the contact quality of the O2 electrode
A 14-bit unsigned integer that represents the contact quality of the O1 electrode
An object with x
and y
values that represent left/right and up/down tilt of the head.
A 7-bit value that represents the momentary left/right rotation of the head.
A 7-bit value that represents the momentary up/down tilt of the head.
wits
has been born as part of brain-bits, an open source P300 speller. I subsequently thought it would be a better idea to make it into its own module, maybe creating a new standard interface for EEG headsets.
wits
currently works with the first iteration of the EPOC headset, and not the EPOC+. This is the limitation of the underlying openyou/emokit-c library.
Here are a few useful features for the future:
- A band-pass filtered version alongside the raw data for easier plotting / operation
- Providing alpha / beta / theta / gamma band powers
- Incorporate more headsets so that
wits
become a universal library for EEG headsets - A modular interface for easily incorporating middleware / processors (for classification or feature extraction)
wits
is meant to simplify BCI development and is under heavy development. We would therefore appreciate if you gave us a hand.
If you would like to see a feature implemented or want to contribute a new feature, you are welcome to open an issue to discuss it and we will be more than happy to help.
If you choose to make a contribution, please fork this repository, work on a feature and submit a pull request.
Copyright (c) 2018 Armagan Amcalar
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.