Skip to content
LAM
Read Home Blog
Make Projects HTML Tools Games
Touch grass Notes Resume Links
Home Blog HTML Projects
Tools Games Notes Resume Links
Back DIY BCI Builder Guide Startups
Download Open
Show description 2,383 chars · Startups

DIY BCI Builder Guide

DIY BCI Builder Guide
















DIY BCI Guide


Overview
Shopping List
Fabrication
Software Setup
Run System
Next Steps













Project Overview

This guide provides a complete roadmap for building a personal, research-grade Brain-Computer Interface (BCI) using OpenBCI hardware, a Raspberry Pi, and your Mac. We'll follow a hybrid "buy and create" model: purchasing the core electronics and 3D printing the headset chassis. This approach offers the best balance of cost, capability, and hands-on creation.



System Architecture

The system is composed of three main parts that work together to capture, process, and stream brainwave data. The headset acquires the raw EEG signals, a Raspberry Pi acts as a dedicated data hub, and your Mac serves as the development and analysis workstation. This dual-platform design provides both portability and power.




🧠

Acquisition Headset

3D-Printed Ultracortex with OpenBCI Cyton board captures raw EEG signals.




--->




🍓

Headless Hub

Raspberry Pi runs a Python script to manage and stream data wirelessly.




--->




💻

Development Workstation

Your Mac receives the data stream for analysis, visualization, and app development.








Important Disclaimer: This project is for educational and development purposes only. The resulting device is not a medical device and should not be used for diagnosis or treatment.








Interactive Shopping List

This section provides a complete, interactive checklist of all components required for the project. Check off items as you acquire them to track your progress and budget. The list is broken down into categories: the core BCI system you'll purchase from OpenBCI, the Raspberry Pi control hub, and the materials and tools you'll need for 3D printing and assembly.









Cost Breakdown






Estimated Total:

$0.00














Fabrication & Assembly

This is the hands-on part of the project. Here, you'll find instructions for 3D printing the Ultracortex headset components and a step-by-step guide to assemble the entire device, from bonding the frame to wiring the electrodes. Precision and patience are key to building a functional and reliable headset.





1. 3D Printing the Ultracortex


The first step is to fabricate the headset's chassis.…

DIY BCI Builder Guide

35,774 bytes · HTML source
<!DOCTYPE html>
<html lang="en" class="scroll-smooth">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DIY BCI Builder Guide</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
    <!-- Chosen Palette: Neuro-Tech Neutral -->
    <!-- Application Structure Plan: The SPA is designed as a task-oriented project dashboard, replacing the linear report structure. A fixed sidebar navigation allows users to jump between key project phases: Overview, Shopping List, Fabrication, Software Setup, and System Run. This non-linear structure is more usable for a long-term project, as users will revisit specific sections (like assembly or code) multiple times. Key interactions include an interactive checklist for the Bill of Materials with a dynamic cost calculator, a step-by-step visual assembly guide, and one-click copyable code blocks, all designed to streamline the complex process of building the BCI. -->
    <!-- Visualization & Content Choices: 
    - Report Info: Bill of Materials (Table 1). Goal: Manage procurement. Viz: Interactive HTML checklist. Interaction: Checkboxes update a running total cost. Justification: More functional and engaging than a static table. Library: Vanilla JS.
    - Report Info: Component Costs. Goal: Visualize budget allocation. Viz: Donut Chart. Interaction: Hover tooltips show details. Justification: Provides a quick, high-level understanding of project expenses. Library: Chart.js.
    - Report Info: System Architecture. Goal: Explain data flow. Viz: HTML/CSS diagram. Interaction: Hover effects for component details. Justification: Integrates seamlessly with app styling and is more flexible than a static image. Library: Tailwind CSS.
    - Report Info: Assembly Steps. Goal: Guide construction. Viz: Numbered HTML cards. Interaction: N/A (clarity through layout). Justification: Breaks a complex process into clear, sequential steps. Library: Tailwind CSS.
    - Report Info: Code Snippets. Goal: Easy code reuse. Viz: Pre-formatted code blocks. Interaction: Copy-to-clipboard button. Justification: Standard UX for technical documentation. Library: Vanilla JS. -->
    <!-- CONFIRMATION: NO SVG graphics used. NO Mermaid JS used. -->
    <style>
        body {
            font-family: 'Inter', sans-serif;
            background-color: #f8fafc; /* slate-50 */
        }
        .chart-container {
            position: relative;
            width: 100%;
            max-width: 400px;
            margin-left: auto;
            margin-right: auto;
            height: 400px;
            max-height: 40vh;
        }
        .nav-link.active {
            background-color: #e2e8f0; /* slate-200 */
            color: #0f172a; /* slate-900 */
            font-weight: 600;
        }
        .nav-link {
            transition: all 0.2s ease-in-out;
        }
        .code-block {
            position: relative;
            background-color: #1e293b; /* slate-800 */
            color: #e2e8f0; /* slate-200 */
            border-radius: 0.5rem;
            padding: 1rem;
            overflow-x: auto;
        }
        .copy-btn {
            position: absolute;
            top: 0.5rem;
            right: 0.5rem;
            background-color: #475569; /* slate-600 */
            color: #f1f5f9; /* slate-100 */
            border: none;
            padding: 0.25rem 0.5rem;
            border-radius: 0.25rem;
            cursor: pointer;
            font-size: 0.75rem;
            transition: background-color 0.2s;
        }
        .copy-btn:hover {
            background-color: #64748b; /* slate-500 */
        }
        .step-card {
            border-left: 4px solid #3b82f6; /* blue-500 */
        }
    </style>
</head>
<body class="text-slate-700">

    <div class="flex min-h-screen">
        <!-- Sidebar Navigation -->
        <aside id="sidebar" class="w-64 bg-white border-r border-slate-200 p-4 fixed top-0 left-0 h-full transform -translate-x-full md:translate-x-0 transition-transform duration-300 ease-in-out z-30">
            <h1 class="text-2xl font-bold text-slate-800 mb-8">DIY BCI Guide</h1>
            <nav id="navigation" class="space-y-2">
                <a href="#overview" class="nav-link block px-4 py-2 rounded-md hover:bg-slate-100">Overview</a>
                <a href="#shopping-list" class="nav-link block px-4 py-2 rounded-md hover:bg-slate-100">Shopping List</a>
                <a href="#fabrication" class="nav-link block px-4 py-2 rounded-md hover:bg-slate-100">Fabrication</a>
                <a href="#software" class="nav-link block px-4 py-2 rounded-md hover:bg-slate-100">Software Setup</a>
                <a href="#run-system" class="nav-link block px-4 py-2 rounded-md hover:bg-slate-100">Run System</a>
                <a href="#next-steps" class="nav-link block px-4 py-2 rounded-md hover:bg-slate-100">Next Steps</a>
            </nav>
        </aside>

        <!-- Mobile Nav Toggle -->
        <button id="menu-toggle" class="md:hidden fixed top-4 left-4 z-40 bg-white p-2 rounded-md shadow-md">
            <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path></svg>
        </button>

        <!-- Main Content -->
        <main class="flex-1 md:ml-64 p-4 sm:p-6 lg:p-8">
            
            <!-- Overview Section -->
            <section id="overview" class="mb-16">
                <h2 class="text-4xl font-bold text-slate-900 mb-4">Project Overview</h2>
                <p class="text-lg text-slate-600 mb-8">This guide provides a complete roadmap for building a personal, research-grade Brain-Computer Interface (BCI) using OpenBCI hardware, a Raspberry Pi, and your Mac. We'll follow a hybrid "buy and create" model: purchasing the core electronics and 3D printing the headset chassis. This approach offers the best balance of cost, capability, and hands-on creation.</p>
                
                <div class="bg-white p-6 rounded-lg shadow-sm">
                    <h3 class="text-2xl font-semibold text-slate-800 mb-4">System Architecture</h3>
                    <p class="mb-6">The system is composed of three main parts that work together to capture, process, and stream brainwave data. The headset acquires the raw EEG signals, a Raspberry Pi acts as a dedicated data hub, and your Mac serves as the development and analysis workstation. This dual-platform design provides both portability and power.</p>
                    <div class="flex flex-col md:flex-row items-center justify-around space-y-6 md:space-y-0 md:space-x-4 text-center">
                        <!-- Acquisition Headset -->
                        <div class="flex flex-col items-center p-4 rounded-lg w-full md:w-1/3">
                            <div class="text-5xl mb-2">🧠</div>
                            <h4 class="font-bold text-slate-800">Acquisition Headset</h4>
                            <p class="text-sm text-slate-500">3D-Printed Ultracortex with OpenBCI Cyton board captures raw EEG signals.</p>
                        </div>
                        
                        <div class="text-2xl text-slate-400 font-mono self-center transform rotate-90 md:rotate-0">---></div>
                        
                        <!-- Headless Hub -->
                        <div class="flex flex-col items-center p-4 rounded-lg w-full md:w-1/3">
                            <div class="text-5xl mb-2">🍓</div>
                            <h4 class="font-bold text-slate-800">Headless Hub</h4>
                            <p class="text-sm text-slate-500">Raspberry Pi runs a Python script to manage and stream data wirelessly.</p>
                        </div>
                        
                        <div class="text-2xl text-slate-400 font-mono self-center transform rotate-90 md:rotate-0">---></div>
                        
                        <!-- Development Workstation -->
                        <div class="flex flex-col items-center p-4 rounded-lg w-full md:w-1/3">
                            <div class="text-5xl mb-2">💻</div>
                            <h4 class="font-bold text-slate-800">Development Workstation</h4>
                            <p class="text-sm text-slate-500">Your Mac receives the data stream for analysis, visualization, and app development.</p>
                        </div>
                    </div>
                </div>
                <div class="mt-8 bg-yellow-100 border-l-4 border-yellow-500 text-yellow-800 p-4 rounded-md">
                    <p><strong class="font-bold">Important Disclaimer:</strong> This project is for educational and development purposes only. The resulting device is not a medical device and should not be used for diagnosis or treatment.</p>
                </div>
            </section>

            <!-- Shopping List Section -->
            <section id="shopping-list" class="mb-16">
                <h2 class="text-4xl font-bold text-slate-900 mb-4">Interactive Shopping List</h2>
                <p class="text-lg text-slate-600 mb-8">This section provides a complete, interactive checklist of all components required for the project. Check off items as you acquire them to track your progress and budget. The list is broken down into categories: the core BCI system you'll purchase from OpenBCI, the Raspberry Pi control hub, and the materials and tools you'll need for 3D printing and assembly.</p>
                
                <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
                    <div id="checklist-container" class="lg:col-span-2 bg-white p-6 rounded-lg shadow-sm">
                        <!-- Checklist will be dynamically generated here -->
                    </div>
                    <div class="lg:col-span-1">
                        <div class="bg-white p-6 rounded-lg shadow-sm sticky top-8">
                            <h3 class="text-2xl font-semibold text-slate-800 mb-4">Cost Breakdown</h3>
                            <div class="chart-container mb-4">
                                <canvas id="costChart"></canvas>
                            </div>
                            <div class="text-center">
                                <p class="text-slate-600">Estimated Total:</p>
                                <p id="total-cost" class="text-4xl font-bold text-slate-800">$0.00</p>
                            </div>
                        </div>
                    </div>
                </div>
            </section>

            <!-- Fabrication Section -->
            <section id="fabrication" class="mb-16">
                <h2 class="text-4xl font-bold text-slate-900 mb-4">Fabrication & Assembly</h2>
                <p class="text-lg text-slate-600 mb-8">This is the hands-on part of the project. Here, you'll find instructions for 3D printing the Ultracortex headset components and a step-by-step guide to assemble the entire device, from bonding the frame to wiring the electrodes. Precision and patience are key to building a functional and reliable headset.</p>
                
                <div class="space-y-12">
                    <!-- 3D Printing -->
                    <div>
                        <h3 class="text-2xl font-semibold text-slate-800 mb-4">1. 3D Printing the Ultracortex</h3>
                        <div class="bg-white p-6 rounded-lg shadow-sm space-y-4">
                            <p>The first step is to fabricate the headset's chassis. You must download the official STL files from the <a href="https://github.com/OpenBCI/Ultracortex/tree/master/Mark_IV/MarkIV-FINAL/STL_Directory" target="_blank" class="text-blue-600 hover:underline">OpenBCI GitHub repository</a> to ensure compatibility with the purchased kit components.</p>
                            <p><strong>Crucial Tip:</strong> Print the two large frame halves with their flat, bisected side directly on the build plate. This minimizes the need for supports and reduces warping. Use PLA filament and consider slowing your print speed for better detail.</p>
                            <div class="overflow-x-auto">
                                <table class="min-w-full text-sm text-left">
                                    <thead class="bg-slate-100 text-slate-600 uppercase">
                                        <tr>
                                            <th class="p-3">Part Name</th>
                                            <th class="p-3">Material</th>
                                            <th class="p-3">Layer Height</th>
                                            <th class="p-3">Infill</th>
                                            <th class="p-3">Supports</th>
                                        </tr>
                                    </thead>
                                    <tbody class="divide-y divide-slate-200">
                                        <tr class="bg-white">
                                            <td class="p-3 font-medium">FRAME_FRONT & BACK</td>
                                            <td class="p-3">PLA</td>
                                            <td class="p-3">0.2 mm</td>
                                            <td class="p-3">20%</td>
                                            <td class="p-3">YES</td>
                                        </tr>
                                        <tr class="bg-white">
                                            <td class="p-3 font-medium">MECH_PARTS (INSERTS)</td>
                                            <td class="p-3">PLA</td>
                                            <td class="p-3">0.2 mm</td>
                                            <td class="p-3">20%</td>
                                            <td class="p-3">NO</td>
                                        </tr>
                                        <tr class="bg-white">
                                            <td class="p-3 font-medium">BOARD_MOUNT & COVER</td>
                                            <td class="p-3">PLA</td>
                                            <td class="p-3">0.2 mm</td>
                                            <td class="p-3">20%</td>
                                            <td class="p-3">NO</td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </div>
                    
                    <!-- Assembly Guide -->
                    <div>
                        <h3 class="text-2xl font-semibold text-slate-800 mb-4">2. Step-by-Step Assembly</h3>
                        <div class="space-y-6">
                            <div class="step-card bg-white p-6 rounded-lg shadow-sm">
                                <h4 class="font-bold text-lg text-slate-800 mb-2">Step 1: Frame Assembly</h4>
                                <p>Carefully align the two 3D-printed frame halves. Apply a thin layer of cyanoacrylate super glue to the mating edges, press firmly together on a flat surface, and hold until the bond is set.</p>
                            </div>
                            <div class="step-card bg-white p-6 rounded-lg shadow-sm">
                                <h4 class="font-bold text-lg text-slate-800 mb-2">Step 2: Install Mechanical Inserts</h4>
                                <p>Press-fit and glue the 35 small, 3D-printed `INSERT` pieces into the octagonal nodes from the inside of the frame. They should sit flush with the inner surface.</p>
                            </div>
                            <div class="step-card bg-white p-6 rounded-lg shadow-sm">
                                <h4 class="font-bold text-lg text-slate-800 mb-2">Step 3: Mount the Cyton Board</h4>
                                <p>Secure the `BOARD_MOUNT` to the back of the frame. Connect the battery to the Cyton board, then carefully fold the battery and wires behind it before snapping the whole assembly into the mount.</p>
                            </div>
                            <div class="step-card bg-white p-6 rounded-lg shadow-sm">
                                <h4 class="font-bold text-lg text-slate-800 mb-2">Step 4: Install Electrodes</h4>
                                <p>Screw the electrode units (spikey for hair, flat for bare skin) into the `INSERT`s. A good starting 8-channel layout is Fp1, Fp2, C3, C4, P7, P8, O1, O2. Use the comfort units on unused top nodes to distribute weight.</p>
                            </div>
                            <div class="step-card bg-white p-6 rounded-lg shadow-sm">
                                <h4 class="font-bold text-lg text-slate-800 mb-2">Step 5: Wire the Electrodes</h4>
                                <p>This is the most critical step. Connect the ribbon cables from the electrodes to the correct input pins on the Cyton board. The ear clips connect to the `SRB2` (Reference) and `BIAS` (Ground) pins for noise cancellation.</p>
                                <div class="overflow-x-auto mt-4">
                                    <table class="min-w-full text-sm text-left">
                                        <thead class="bg-slate-100 text-slate-600 uppercase">
                                            <tr><th class="p-3">Channel</th><th class="p-3">10-20 Location</th><th class="p-3">Cyton Pin</th></tr>
                                        </thead>
                                        <tbody class="divide-y divide-slate-200">
                                            <tr class="bg-white"><td>1-8</td><td>Fp1, Fp2, C3, C4, P7, P8, O1, O2</td><td>N1P - N8P (Top Row)</td></tr>
                                            <tr class="bg-white"><td>REF</td><td>Left Ear Lobe</td><td>SRB2 (Bottom Row)</td></tr>
                                            <tr class="bg-white"><td>BIAS</td><td>Right Ear Lobe</td><td>BIAS (Bottom Row)</td></tr>
                                        </tbody>
                                    </table>
                                </div>
                            </div>
                             <div class="bg-red-100 border-l-4 border-red-500 text-red-800 p-4 rounded-md">
                                <p><strong class="font-bold">Critical Warning:</strong> Before twisting an electrode to adjust its height, ALWAYS disconnect its wire from the board. Twisting while connected will break the internal wire and is not covered by warranty.</p>
                            </div>
                        </div>
                    </div>
                </div>
            </section>

            <!-- Software Section -->
            <section id="software" class="mb-16">
                <h2 class="text-4xl font-bold text-slate-900 mb-4">Software Configuration</h2>
                <p class="text-lg text-slate-600 mb-8">With the hardware built, it's time to bring it to life with software. This section guides you through setting up your development environment on both macOS and the Raspberry Pi. We'll use the OpenBCI GUI for initial hardware checks and the powerful BrainFlow library for writing custom applications. The most challenging part is compiling BrainFlow from source on the Pi, a necessary step for its ARM processor.</p>
                
                <div class="space-y-12">
                     <div>
                        <h3 class="text-2xl font-semibold text-slate-800 mb-4">macOS: Your Development Workstation</h3>
                        <div class="bg-white p-6 rounded-lg shadow-sm space-y-4">
                            <p><strong>1. Install OpenBCI GUI:</strong> Download from the OpenBCI website. On first launch, you may need to right-click and select "Open" to bypass security warnings.</p>
                            <p><strong>2. First Connection:</strong> Plug in the USB dongle (switch on `GPIO6`), power on the Cyton, and launch the GUI. Select the correct serial port (e.g., `/dev/tty.usbserial-DN00nnnn`) and click `Start Data Stream` to verify you are receiving data.</p>
                            <p><strong>3. Setup Python Environment:</strong> Use a virtual environment and install BrainFlow.</p>
                            <pre class="code-block"><button class="copy-btn">Copy</button><code>python3 -m venv bci-env
source bci-env/bin/activate
pip install brainflow numpy pandas matplotlib</code></pre>
                            <p><strong>4. Test Script:</strong> Run this script to confirm your BrainFlow setup can connect to the board directly from your Mac.</p>
                            <pre class="code-block"><button class="copy-btn">Copy</button><code>import time
from brainflow.board_shim import BoardShim, BrainFlowInputParams, BoardIds

params = BrainFlowInputParams()
# IMPORTANT: Replace with your serial port
params.serial_port = '/dev/tty.usbserial-DN00nnnn' 
board_id = BoardIds.CYTON_BOARD.value
board = BoardShim(board_id, params)
board.prepare_session()
board.start_stream()
time.sleep(5)
data = board.get_board_data()
board.stop_stream()
board.release_session()
print(f"Data acquired! Shape: {data.shape}")</code></pre>
                        </div>
                    </div>

                    <div>
                        <h3 class="text-2xl font-semibold text-slate-800 mb-4">Raspberry Pi: Your Headless BCI Hub</h3>
                        <div class="bg-white p-6 rounded-lg shadow-sm space-y-4">
                            <p><strong>1. Prepare Pi:</strong> Flash Raspberry Pi OS Lite (64-bit) to a microSD card, enable SSH, and connect to it from your Mac.</p>
                            <p><strong>2. Compile BrainFlow from Source:</strong> This is a mandatory and time-consuming step. Run these commands on the Pi.</p>
                            <pre class="code-block"><button class="copy-btn">Copy</button><code># Install dependencies
sudo apt update && sudo apt install -y build-essential git cmake python3-pip

# Clone and build BrainFlow
git clone --recursive https://github.com/brainflow-dev/brainflow.git
cd brainflow
python3 tools/build.py

# Install Python bindings
cd python-package
pip install .</code></pre>
                        </div>
                    </div>
                </div>
            </section>

            <!-- Run System Section -->
            <section id="run-system" class="mb-16">
                <h2 class="text-4xl font-bold text-slate-900 mb-4">Running the Full System</h2>
                <p class="text-lg text-slate-600 mb-8">The final step is to connect the two systems, creating a wireless data pipeline from your BCI headset to your Mac. The Raspberry Pi will act as a server, capturing data from the Cyton board and streaming it over your local network using the Open Sound Control (OSC) protocol. A corresponding script on your Mac will listen for this data, making it available for your applications.</p>
                <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
                    <div class="bg-white p-6 rounded-lg shadow-sm">
                        <h3 class="text-xl font-semibold text-slate-800 mb-2">1. Pi Hub Streamer Script</h3>
                        <p class="text-sm mb-4">Create this file (`pi_hub_streamer.py`) on your Raspberry Pi. It connects to the Cyton and sends EEG data to your Mac's IP address. First run `pip install python-osc`.</p>
                        <pre class="code-block"><button class="copy-btn">Copy</button><code>import time, argparse
from brainflow.board_shim import BoardShim, BrainFlowInputParams, BoardIds
from pythonosc import udp_client

parser = argparse.ArgumentParser()
parser.add_argument("--ip", default="192.168.1.100", help="Mac's IP")
args = parser.parse_args()

client = udp_client.SimpleUDPClient(args.ip, 5005)
params = BrainFlowInputParams()
params.serial_port = '/dev/ttyUSB0'
board = BoardShim(BoardIds.CYTON_BOARD.value, params)
eeg_channels = BoardShim.get_eeg_channels(BoardIds.CYTON_BOARD.value)

board.prepare_session()
board.start_stream()
print("Pi Hub streaming started...")
while True:
    data = board.get_current_board_data(25)
    if data.shape[1] > 0:
        for sample in data[eeg_channels].T:
            client.send_message("/eeg", sample.tolist())
    time.sleep(0.02)</code></pre>
                    </div>
                    <div class="bg-white p-6 rounded-lg shadow-sm">
                        <h3 class="text-xl font-semibold text-slate-800 mb-2">2. Mac Receiver Script</h3>
                        <p class="text-sm mb-4">Create this file (`mac_receiver.py`) on your Mac. It starts a server that listens for and prints the EEG data coming from the Pi. First run `pip install python-osc`.</p>
                         <pre class="code-block"><button class="copy-btn">Copy</button><code>import argparse
from pythonosc import dispatcher, osc_server

def eeg_handler(address, *args):
    print(f"EEG Data Received: {args}")

parser = argparse.ArgumentParser()
parser.add_argument("--ip", default="0.0.0.0")
parser.add_argument("--port", type=int, default=5005)
args = parser.parse_args()

disp = dispatcher.Dispatcher()
disp.map("/eeg", eeg_handler)

server = osc_server.ThreadingOSCUDPServer((args.ip, args.port), disp)
print(f"Serving on {server.server_address}")
server.serve_forever()</code></pre>
                    </div>
                </div>
                <div class="mt-8 bg-green-100 border-l-4 border-green-500 text-green-800 p-4 rounded-md">
                    <h4 class="font-bold">To Launch:</h4>
                    <ol class="list-decimal list-inside mt-2">
                        <li>Find your Mac's local IP address.</li>
                        <li>On the Pi, run: `python pi_hub_streamer.py --ip <your_mac_ip_address>`</li>
                        <li>On the Mac, run: `python mac_receiver.py`</li>
                        <li>You should see EEG data printing in your Mac's terminal!</li>
                    </ol>
                </div>
            </section>

            <!-- Next Steps Section -->
            <section id="next-steps" class="mb-16">
                <h2 class="text-4xl font-bold text-slate-900 mb-4">Conclusion & Next Steps</h2>
                <p class="text-lg text-slate-600 mb-8">Congratulations! You have successfully built a research-grade BCI and established a data pipeline. This is not an end, but a beginning. Your robust and flexible platform is now ready for you to explore the vast world of neurotechnology. The journey into personal BCI development is challenging but rewarding, and you are now equipped to start creating your own applications.</p>
                <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
                    <div class="bg-white p-6 rounded-lg shadow-sm">
                        <h3 class="font-semibold text-slate-800 mb-2">Simple I/O</h3>
                        <p class="text-sm">Use brain states (like relaxation) to control the Raspberry Pi's GPIO pins, lighting an LED or driving a small robot.</p>
                    </div>
                    <div class="bg-white p-6 rounded-lg shadow-sm">
                        <h3 class="font-semibold text-slate-800 mb-2">Neurofeedback</h3>
                        <p class="text-sm">Create applications that provide real-time audio or visual feedback on brain activity to train focus or relaxation.</p>
                    </div>
                    <div class="bg-white p-6 rounded-lg shadow-sm">
                        <h3 class="font-semibold text-slate-800 mb-2">Motor Imagery</h3>
                        <p class="text-sm">Train a machine learning model to recognize the neural signals of imagined movements (e.g., left vs. right hand) to control a cursor.</p>
                    </div>
                    <div class="bg-white p-6 rounded-lg shadow-sm">
                        <h3 class="font-semibold text-slate-800 mb-2">Advanced DSP</h3>
                        <p class="text-sm">Dive deeper into digital signal processing to filter noise and extract features like alpha, beta, and gamma waves from the raw EEG signal.</p>
                    </div>
                </div>
                 <p class="mt-8 text-center text-slate-500">Don't forget to join the <a href="https://openbci.com/forum/" target="_blank" class="text-blue-600 hover:underline">OpenBCI Community Forum</a> to share your progress and get help.</p>
            </section>

        </main>
    </div>

<script>
document.addEventListener('DOMContentLoaded', function () {
    const shoppingListData = [
        {
            category: 'Core BCI System',
            items: [
                { name: 'OpenBCI Cyton Board (8-channel)', cost: 499.99, note: 'The core data acquisition unit.' },
                { name: 'Ultracortex Mark IV "Print-It-Yourself" Kit', cost: 499.99, note: 'Includes all non-printable hardware.' }
            ]
        },
        {
            category: 'Control Hub',
            items: [
                { name: 'Raspberry Pi 4 Starter Kit (8GB)', cost: 125.00, note: 'Includes Pi, case, power supply, etc.' }
            ]
        },
        {
            category: 'Assembly Tools & Materials',
            items: [
                { name: 'PLA Filament (1kg)', cost: 22.00, note: 'Standard material for all 3D printed parts.' },
                { name: 'Loctite Super Glue', cost: 5.00, note: 'For bonding the frame halves.' },
            ]
        }
    ];

    const checklistContainer = document.getElementById('checklist-container');
    const totalCostEl = document.getElementById('total-cost');
    let totalCost = 0;

    function renderChecklist() {
        let html = '';
        shoppingListData.forEach(cat => {
            html += `<h3 class="text-xl font-semibold text-slate-800 mt-6 mb-3 first:mt-0">${cat.category}</h3>`;
            html += '<ul class="space-y-3">';
            cat.items.forEach(item => {
                html += `
                    <li class="flex items-start">
                        <input type="checkbox" data-cost="${item.cost}" class="item-checkbox mt-1 mr-3 h-5 w-5 rounded border-slate-300 text-blue-600 focus:ring-blue-500">
                        <label class="flex-1">
                            <span class="font-medium text-slate-800">${item.name}</span>
                            <p class="text-sm text-slate-500">${item.note}</p>
                            <p class="text-sm font-semibold text-blue-700">$${item.cost.toFixed(2)}</p>
                        </label>
                    </li>
                `;
            });
            html += '</ul>';
        });
        checklistContainer.innerHTML = html;
    }

    function updateTotalCost() {
        totalCost = 0;
        document.querySelectorAll('.item-checkbox:checked').forEach(checkbox => {
            totalCost += parseFloat(checkbox.dataset.cost);
        });
        totalCostEl.textContent = `$${totalCost.toFixed(2)}`;
    }

    function updateChart() {
        const categoryCosts = shoppingListData.map(cat => {
            return cat.items.reduce((sum, item) => sum + item.cost, 0);
        });
        const categoryLabels = shoppingListData.map(cat => cat.category);

        const ctx = document.getElementById('costChart').getContext('2d');
        new Chart(ctx, {
            type: 'doughnut',
            data: {
                labels: categoryLabels,
                datasets: [{
                    label: 'Cost Breakdown',
                    data: categoryCosts,
                    backgroundColor: [
                        'rgba(59, 130, 246, 0.7)',  // blue-500
                        'rgba(239, 68, 68, 0.7)',   // red-500
                        'rgba(245, 158, 11, 0.7)', // amber-500
                    ],
                    borderColor: [
                        'rgba(59, 130, 246, 1)',
                        'rgba(239, 68, 68, 1)',
                        'rgba(245, 158, 11, 1)',
                    ],
                    borderWidth: 1
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        position: 'top',
                    },
                    tooltip: {
                        callbacks: {
                            label: function(context) {
                                let label = context.label || '';
                                if (label) {
                                    label += ': ';
                                }
                                if (context.parsed !== null) {
                                    label += new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(context.parsed);
                                }
                                return label;
                            }
                        }
                    }
                }
            }
        });
    }
    
    checklistContainer.addEventListener('change', (e) => {
        if (e.target.classList.contains('item-checkbox')) {
            updateTotalCost();
        }
    });

    renderChecklist();
    updateTotalCost();
    updateChart();

    // Navigation Logic
    const sections = document.querySelectorAll('section');
    const navLinks = document.querySelectorAll('#navigation a');
    const menuToggle = document.getElementById('menu-toggle');
    const sidebar = document.getElementById('sidebar');

    const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                navLinks.forEach(link => {
                    link.classList.toggle('active', link.getAttribute('href').substring(1) === entry.target.id);
                });
            }
        });
    }, { rootMargin: "-50% 0px -50% 0px" });

    sections.forEach(section => observer.observe(section));

    menuToggle.addEventListener('click', () => {
        sidebar.classList.toggle('-translate-x-full');
    });

    // Copy to clipboard for code blocks
    document.querySelectorAll('.copy-btn').forEach(button => {
        button.addEventListener('click', () => {
            const code = button.nextElementSibling.textContent;
            const textarea = document.createElement('textarea');
            textarea.value = code;
            document.body.appendChild(textarea);
            textarea.select();
            document.execCommand('copy');
            document.body.removeChild(textarea);
            
            button.textContent = 'Copied!';
            setTimeout(() => {
                button.textContent = 'Copy';
            }, 2000);
        });
    });
});
</script>
</body>
</html>