Skip to content

Biofeedback

See how physiological data streaming in from BIOPAC acqknowledge can control an object in the scene. In this case a ball will change in size and color based on the physiological signal.  You may need to adjust the position of the ball down if using 360 media.

import vizshape, vizinfo, viztask
import sightlab_utils.sightlab as sl
from sightlab_utils import biopacndt
from sightlab_utils.settings import *

# Initialize SightLab with Biopac enabled
sightlab = sl.SightLab(biopac=True)
sightlab.setTrialCount(1)

# Load object
ball = vizshape.addSphere(radius=0.2)
ball.setScale(1.2, 1.2, 1.2)
ball.alpha(0.5)
ball.color(viz.BLUE)
ball.setPosition(0, 1.5, 2)
sightlab.addSceneObject('ball', ball)

# Biopac configuration
BUFFER_LENGTH = 2
allchannels = []

def outputToScreen(index, frame, channelsInSlice):
    global allchannels

    for i, value in enumerate(frame):
        rounded_value = round(value, 4)  # Round to 4 decimal places
        # Append value to buffer
        allchannels[i].append(rounded_value)
        if len(allchannels[i]) > BUFFER_LENGTH:
            allchannels[i].pop(0)

        # Log to custom trial data
        sightlab.setCustomTrialData(str(rounded_value), f"Channel_{i}")

        # Update ball position or color
        move = (value - 0.5) * 0.5  # Adjust scaling as needed
        new_y = 1.5 + move
        ball.setPosition(0, new_y, 2)
        if new_y > 1.4:
            ball.color(viz.GREEN)
        elif new_y < 1.0:
            ball.color(viz.RED)
        else:
            ball.color(viz.BLUE)

# Biopac server setup
acqServer = biopacndt.AcqNdtQuickConnect()
enabledChannels = acqServer.DeliverAllEnabledChannels()
dataServer = biopacndt.AcqNdtDataServer(acqServer.getSingleConnectionModePort(), enabledChannels)
dataServer.RegisterCallback("OutputToScreen", outputToScreen)

# Initialize data buffers
for _ in enabledChannels:
    allchannels.append([0] * BUFFER_LENGTH)

# Declare dataServer as a global variable
dataServer = None

# Experiment function
def sightLabExperiment():
    global dataServer
    yield viztask.waitEvent(EXPERIMENT_START)

    for i in range(0, sightlab.getTrialCount()):
        yield viztask.waitKeyDown(' ')
        yield sightlab.startTrial()

        # Stop the dataServer if it exists
        if dataServer:
            print("Stopping previous Biopac data server...")
            dataServer.Stop()

        # Reinitialize Biopac data server for each trial
        print("Initializing Biopac data server...")
        dataServer = biopacndt.AcqNdtDataServer(
            sightlab.acqServer.getSingleConnectionModePort(),
            enabledChannels
        )
        dataServer.RegisterCallback("OutputToScreen", outputToScreen)
        dataServer.Start()

        yield viztask.waitKeyDown(' ')
        yield sightlab.endTrial()
        dataServer.Stop()

# Schedule experiment
viztask.schedule(sightlab.runExperiment)
viztask.schedule(sightLabExperiment)
Was this page helpful?