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.