EEG-Operated Vehicle Control System
Motivation
The primary motivation behind this project is to create an assistive technology that allows individuals with certain disabilities to operate a vehicle using simple, non-invasive EEG signals. By utilizing the Muse headband, we aim to demonstrate that advanced control mechanisms can be achieved with relatively simple and affordable technology. This project showcases how EEG data can be harnessed to enable mobility solutions, contributing to the field of assistive technologies.
Detecting Head Movements
In this function, the 'accForBack' parameter represents the forward-backward tilt of the head. The value of'accForBack'comes from the Muse headband accerometer. If the value is greater than 0.5, it indicates a forward tilt; if less than -0.5, it indicates a backward tilt. The function then sets the appropriate global variables and prints the direction of movement.
# Detecting Head Movements
def dataGyro(none: float, accForBack: float, accLeftRight: float, accZ: float):
global turn_drive_toggle, forward_Back, limitDrive, limiter
if accForBack > 0.5: # Detect head tilting forward
turn_drive_toggle = True
if not forward_Back or limitDrive:
forward_Back = True
limitDrive = False
limiter = True
print("Forward")
elif accForBack < -0.5: # Detect head tilting backward
turn_drive_toggle = True
if forward_Back or limitDrive:
forward_Back = False
limitDrive = False
limiter = True
print("Backward")
# Detecting Jaw Clenching
def action(eegTP9, eegAF7, eegAF8, eegTP10):
global eegAF7Array, timeArray, turn_drive_toggle, left_right_toggle, limitDrive, forward_Back, limiter
average = 0
yf = rfft(eegAF7Array[:sample])
xf = rfftfreq(len(npArray[:sample]),1/sample)
absYF = np.abs(yf)
power_spectrum = np.square(absYF)
#Artifacts found between above 48 hertz and below 5 Hertz, so we set these to 0 in the power spectrum
for j in range(0,len(xf)):
for j in range(0,len(xf)):
if (xf[j]< 5 or xf[j] > 48) :
power_spectrum[j] = 0
arrayPower = findMaximumFreq(power_spectrum,xf)
#average of top 3 powerful frequencies is calculated to detect jaw cletching
average = (arrayPower[0]+arrayPower[1]+arrayPower[2])/3
#...
if average >= 25:
if turn_drive_toggle:
if forward_Back:
m.forward(1)
else:
m.reverse(1)
else:
if left_right_toggle:
m.right(1)
else:
m.left(1)
Detecting Jaw Clenching
In this function, EEG data is continuously collected and stored in arrays. We found that the AF7 EEG channel provided the highest signal-to-noise ratio possibly due to the electrode having the best contact with the skin.
When the length of the array exceeds 2048, older data is discarded to keep the array size constant. The FFT is performed on the EEG data to analyze its frequency components. The power spectral density (PSD) is calculated, and the average power in the 20-30 Hz range is used to detect jaw clenching. If the average power exceeds a threshold (25 in this case), the vehicle moves based on the current mode (forward/backward or left/right).
Detecting Blinks
This code iterates through the EEG data to detect a blink by finding a high signal (greater than 1050.0) followed by a low signal (less than 700.0). If both conditions are met and the limiter is not active, it toggles the turning mode (left or right) and prints the current direction.
We chose these threshold numbers to minimise our chance of getting false positives from natural eye blinks. The user needs to intentionally blink hard for an eye blink to be detected.
# Detecting Blinks
for i in range(len(eegAF7Array)):
if float(eegAF7Array[i]) > 1050.0: # Detect high EEG signal
high1000 = True
indexRemember = i
break
if high1000:
for i in range(indexRemember, len(eegAF7Array)):
if float(eegAF7Array[i]) < 700.0: # Detect subsequent low EEG signal
low9000 = True
break
if high1000 and low9000 and not limiter:
turn_drive_toggle = False
limitDrive = True
left_right_toggle = not left_right_toggle
print("Left" if not left_right_toggle else "Right")
More Information
For more information check out the github for this project. Feel free to contact me if you have any questions.