UE4读取脑电波MindWave插件(展示如何使用第三方库制作UE4插件)

Posted 酷熊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UE4读取脑电波MindWave插件(展示如何使用第三方库制作UE4插件)相关的知识,希望对你有一定的参考价值。

MyEEGPlugin.uplugin

{
    "FileVersion": 3,
    "Version": 1,
    "VersionName": "1.0",
    "FriendlyName": "MyEEGPlugin",
    "Description": "",
    "Category": "Other",
    "CreatedBy": "",
    "CreatedByURL": "",
    "DocsURL": "",
    "MarketplaceURL": "",
    "SupportURL": "",
    "CanContainContent": true,
    "IsBetaVersion": false,
    "Installed": false,
    "Modules": [
        {
            "Name": "MyEEGPlugin",
            "Type": "Runtime",
            "LoadingPhase": "Default"
        }
    ]
}

MyEEGPlugin.Build.cs

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;
using System.IO;

public class MyEEGPlugin : ModuleRules
{
    public MyEEGPlugin(TargetInfo Target)
    {
        
        PublicIncludePaths.AddRange(
            new string[] {
                "MyEEGPlugin/Public"
                // ... add public include paths required here ...
            }
            );
                
        
        PrivateIncludePaths.AddRange(
            new string[] {
                "MyEEGPlugin/Private",
                // ... add other private include paths required here ...
            }
            );
            
        
        PublicDependencyModuleNames.AddRange(
            new string[]
            {
                "Core", "CoreUObject", "Engine", "InputCore", "Projects"
                // ... add other public dependencies that you statically link with here ...
            }
            );
            
        
        PrivateDependencyModuleNames.AddRange(
            new string[]
            {
                // ... add private dependencies that you statically link with here ...    
            }
            );
        
        
        DynamicallyLoadedModuleNames.AddRange(
            new string[]
            {
                // ... add any modules that your module loads dynamically here ...
            }
            );

        LoadThinkGearLib(Target);//添加第三方库
        //LoadAlgoSdkDll(Target);//添加第三方库
    }

    private string ThirdPartyPath
    {
        get
        {
            return Path.GetFullPath(Path.Combine(ModuleDirectory, "../ThirdParty/"));
        }
    }

    public void LoadThinkGearLib(TargetInfo Target)
    {
        if ((Target.Platform == UnrealTargetPlatform.Win64) || (Target.Platform == UnrealTargetPlatform.Win32))
        {
            string PlatformString = (Target.Platform == UnrealTargetPlatform.Win64) ? "64" : "";
            string LibrariesPath = Path.Combine(ThirdPartyPath, "ThinkGear", "lib");
            
            //test your path
            System.Console.WriteLine("... LibrariesPath -> " + LibrariesPath);

            PublicIncludePaths.Add(Path.Combine(ThirdPartyPath, "ThinkGear", "include"));
            PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, "thinkgear" + PlatformString + ".lib"));
        }

        //Definitions.Add(string.Format("MY_DEFINE={0}", 0));
    }

    public void LoadAlgoSdkDll(TargetInfo Target)
    {
        if ((Target.Platform == UnrealTargetPlatform.Win64) || (Target.Platform == UnrealTargetPlatform.Win32))
        {
            string PlatformString = (Target.Platform == UnrealTargetPlatform.Win64) ? "64" : "";
            string DllPath = Path.Combine(ThirdPartyPath, "bin", "AlgoSdkDll" + PlatformString + ".dll");

            PublicIncludePaths.Add(Path.Combine(ThirdPartyPath, "EEGAlgoSDK", "include"));
            PublicDelayLoadDLLs.Add(DllPath);
            //RuntimeDependencies.Add(new RuntimeDependency(DllPath));
        }
    }

}

MyEEGPlugin.h

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "ModuleManager.h"

class FMyEEGPluginModule : public IModuleInterface
{
public:

    /** IModuleInterface implementation */
    virtual void StartupModule() override;
    virtual void ShutdownModule() override;

private:
    /** Handle to the test dll we will load */
    void*    ExampleLibraryHandle;
};

MyEEGPlugin.cpp

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.

#include "MyEEGPlugin.h"
#include "Core.h"
#include "ModuleManager.h"
#include "IPluginManager.h"
//#include "ExampleLibrary.h"

#define LOCTEXT_NAMESPACE "FMyEEGPluginModule"

void FMyEEGPluginModule::StartupModule()
{
    // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module

    // Get the base directory of this plugin
    FString BaseDir = IPluginManager::Get().FindPlugin("MyEEGPlugin")->GetBaseDir();

    // Add on the relative location of the third party dll and load it
    FString LibraryPath;
#if PLATFORM_WINDOWS
    LibraryPath = FPaths::Combine(*BaseDir, TEXT("Binaries/ThirdParty/MyEEGPluginLibrary/Win64/ExampleLibrary.dll"));
#elif PLATFORM_MAC
    LibraryPath = FPaths::Combine(*BaseDir, TEXT("Source/ThirdParty/MyEEGPluginLibrary/Mac/Release/libExampleLibrary.dylib"));
#endif // PLATFORM_WINDOWS

    ExampleLibraryHandle = !LibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*LibraryPath) : nullptr;

    if (ExampleLibraryHandle)
    {
        // Call the test function in the third party library that opens a message box
        //ExampleLibraryFunction();
    }
    else
    {
        //FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ThirdPartyLibraryError", "Failed to load example third party library"));
    }
}

void FMyEEGPluginModule::ShutdownModule()
{
    // This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
    // we call this function before unloading the module.

    // Free the dll handle
    FPlatformProcess::FreeDllHandle(ExampleLibraryHandle);
    ExampleLibraryHandle = nullptr;
}

#undef LOCTEXT_NAMESPACE
    
IMPLEMENT_MODULE(FMyEEGPluginModule, MyEEGPlugin)

MyEEGReceiver.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once
#include "Engine.h"
#include "GameFramework/Actor.h"
#include "MyEEGReceiver.generated.h"

UCLASS()
class AMyEEGReceiver : public AActor
{
    GENERATED_BODY()
    
public:    
    // Sets default values for this actor\'s properties
    AMyEEGReceiver();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;
    int rawDataIndex;
    int lerpDataIndex;
    float totalAngle;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    float v;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    float s;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    float a;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    TArray<float> rawAttentions;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    TArray<float> rawMeditations;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    TArray<float> lerpAttentions;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    TArray<float> lerpMeditations;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    float attention1;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    float attention2;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    float meditation1;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    float meditation2;
public:    
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    /** Called whenever this actor is being removed from a level */
    virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

    
    UFUNCTION(BlueprintImplementableEvent, Category = "EEG")
    void BPEvent_GetNewAttention(float newAttention);
    
    UFUNCTION(BlueprintCallable, Category = "EEG")
    void IndexFunc();

    UFUNCTION(BlueprintCallable, Category = "EEG")
    void ComputeNewPos(float factor, UStaticMeshComponent* cube, float DeltaTime, float scaleFactorAtten=1, float scaleFactorMedi = 1, bool debug=false);

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    int32 LatestMeditation;        //最新放松度
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    int32 LatestAttention;        //最新专注度

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EEG")
    bool ShowOnScreenDebugMessages;
    
    FORCEINLINE void ScreenMsg(const FString& Msg)
    {
        if (!ShowOnScreenDebugMessages) return;
        GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, *Msg);
    }
    FORCEINLINE void ScreenMsg(const FString& Msg, const int32 Value)
    {
        if (!ShowOnScreenDebugMessages) return;
        GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("%s %d"), *Msg, Value));
    }
};

MyEEGReceiver.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "MyEEGPlugin.h"
#include "MyEEGReceiver.h"
#include "thinkgear.h"

#define NUM 3
// Sets default values
AMyEEGReceiver::AMyEEGReceiver()
{
     // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don\'t need it.
    PrimaryActorTick.bCanEverTick = true;

    ShowOnScreenDebugMessages = true;
    v = 0; a = 1; s = 0;
    rawDataIndex = 0;
    lerpDataIndex = 0;
    rawAttentions.Init(0, NUM);
    rawMeditations.Init(0, NUM);
    totalAngle = 0;
}

long raw_data_count = 0;
short *raw_data = NULL;
bool bRunning = false;
bool bInited = false;
char *comPortName = NULL;
int   dllVersion = 0;
int   connectionId = -1;
int   packetsRead = 0;
int   errCode = 0;
bool bConnectedHeadset = false;


// Called when the game starts or when spawned
void AMyEEGReceiver::BeginPlay()
{
    Super::BeginPlay();

    /* Print driver version number */
    dllVersion = TG_GetVersion();
    ScreenMsg("ThinkGear DLL version:",dllVersion);
    //GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ThinkGear DLL version: %d\\n"), dllVersion));
    /* Get a connection ID handle to ThinkGear */
    connectionId = TG_GetNewConnectionId();
    if (connectionId < 0) {
        ScreenMsg("Failed to new connection ID");
    }
    else {
        /* Attempt to connect the connection ID handle to serial port "COM5" */
        /* NOTE: On Windows, COM10 and higher must be preceded by \\\\.\\, as in
        *       "\\\\\\\\.\\\\COM12" (must escape backslashes in strings).  COM9
        *       and lower do not require the \\\\.\\, but are allowed to include
        *       them.  On Mac OS X, COM ports are named like
        *       "/dev/tty.MindSet-DevB-1".
        */
        comPortName = "\\\\\\\\.\\\\COM6";
        errCode = TG_Connect(connectionId,
            comPortName,
            TG_BAUD_57600,
            TG_STREAM_PACKETS);
        if (errCode < 0) 
        {
            ScreenMsg("TG_Connect() failed", errCode);
        }
        else
        {
            ScreenMsg("TG_Connect OK",connectionId);
        }
    }

}

// Called every frame
void AMyEEGReceiver::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    v = v + a*DeltaTime;
    s += v*DeltaTime;
    /* Read all currently available Packets, one at a time... */
    do {
        /* Read a single Packet from the connection */
        packetsRead = TG_ReadPackets(connectionId, 1);
        
        /* If TG_ReadPackets() was able to read a Packet of data... */
        if (packetsRead == 1) {
            //ScreenMsg("TG_ReadPackets");
            /* If the Packet containted a new raw wave value... */
            if (TG_GetValueStatus(connectionId, TG_DATA_RAW) != 0) {
                int rawData = (int)TG_GetValue(connectionId, TG_DATA_RAW);
                //ScreenMsg("TG_DATA_RAW",rawData);
            } /* end "If Packet contained a raw wave value..." */

            if (TG_GetValueStatus(connectionId, TG_DATA_POOR_SIGNAL) != 0) {
                int ps=TG_GetValue(connectionId, TG_DATA_POOR_SIGNAL);
                //ScreenMsg("TG_DATA_POOR_SIGNAL",ps);
            }

            if (TG_GetValueStatus(connectionId, TG_DATA_MEDITATION) != 0) {
                float medi = TG_GetValue(connectionId, TG_DATA_MEDITATION);
                LatestMeditation = (int32)medi;
                //ScreenMsg("TG_DATA_MEDITATION", LatestMeditation);
                rawMeditations[rawDataIndex] = medi;
                float total = 0;
                for (int i = 0; i < NUM; i++)
                    total += rawMeditations[i];
                float avg_medi = total / NUM;
                lerpMeditations.Add(avg_medi);
            }

            if (TG_GetValueStatus(connectionId, TG_DATA_ATTENTION) != 0) {
                float atten = TG_GetValue(connectionId, TG_DATA_ATTENTION);
                LatestAttention = (int32)atten;
                rawAttentions[rawDataIndex] = atten;
                float total = 0;
                for (int i = 0; i < NUM; i++)
                    total += rawAttentions[i];
                float avg_atten = total / NUM;
                lerpAttentions.Add(avg_atten);

                rawDataIndex++;
                if (rawDataIndex == NUM)
                {
                    rawDataIndex = 0;
                }

                ScreenMsg("avg_atten", avg_atten);
                //BPEvent_GetNewAttention(TG_GetValue(connectionId, TG_DATA_ATTENTION));
                //float atten=TG_GetValue(connectionId, TG_DATA_ATTENTION);
                //float delta = atten - s;
                //a = delta;
                ScreenMsg("TG_DATA_ATTENTION", LatestAttention);
                //ScreenMsg("delta", delta);
                //ScreenMsg("s", s);
            }

        } /* end "If TG_ReadPackets() was able to read a Packet..." */

    } while (packetsRead > 0); /* Keep looping until all Packets read */
}

void AMyEEGReceiver::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
    Super::EndPlay(EndPlayReason);

    /* Clean up */
    TG_FreeConnection(connectionId);
}

void AMyEEGReceiver::IndexFunc()
{
    int lerpNum = lerpAttentions.Num();
    if (lerpNum ==0)
        return;
    int idx1 = lerpDataIndex - 1;
    int idx2 = lerpDataIndex;
    idx1 = FMath::Max(idx1,0);
    idx2 = FMath::Min(idx2, lerpNum-1);
    attention1 = lerpAttentions[idx1];
    attention2 = lerpAttentions[idx2];
    meditation1 = lerpMeditations[idx1];
    meditation2 = lerpMeditations[idx2];
    if (lerpDataIndex < lerpNum-1)
    {
        lerpDataIndex++;
    }
}

void AMyEEGReceiver::ComputeNewPos(float factor, UStaticMeshComponent* cube, float DeltaTime,
    float scaleFactorAtten/*=1*/, float scaleFactorMedi/* = 1*/, bool debug/* = false*/)
{
    float tmpAtten = FMath::Lerp(attention1, attention2, factor);
    float tmpMedit = FMath::Lerp(meditation1, meditation2, factor);
    static float testTime = 0;
    if (debug)
    {
        tmpMedit = 50 + sin(testTime) * 50;
        tmpAtten = 50 + sin(testTime) * 50; testTime += DeltaTime;
    }
    float s0 = tmpMedit*DeltaTime*scaleFactorMedi;
    FVector oldPos = cube->GetComponentLocation();
    float angle = FMath::Atan(s0 / (oldPos.Size()));
    FVector normalVec = oldPos.GetSafeNormal();
    FVector newPos = normalVec*(10000 + tmpAtten*scaleFactorAtten);
    cube->SetWorldLocation(newPos.RotateAngleAxis(FMath::RadiansToDegrees(angle),FVector(0,1,0)));
    FRotator Rotator = FRotator::ZeroRotator;
    totalAngle += FMath::RadiansToDegrees(angle);
    Rotator.Add(-totalAngle, 0, 0);
    if (totalAngle >= 360)
    {
        totalAngle = 0;
    }
    cube->SetWorldRotation(Rotator);
    UTextRenderComponent* text = dynamic_cast<UTextRenderComponent*>(cube->GetChildComponent(0));
    if (text)
    {
        FString t1 = FString::FromInt(tmpAtten);
        FString t2 = FString::FromInt(tmpMedit);
        FString t3 = FString::FromInt(totalAngle);
        FString tmp(", ");
        tmp = t1 + tmp + t2;
        text->SetText(FText::FromString(tmp));
    }
}

 

以上是关于UE4读取脑电波MindWave插件(展示如何使用第三方库制作UE4插件)的主要内容,如果未能解决你的问题,请参考以下文章

UE4插件-读取png图片

UE4根据真实地图来生成行走道路

Neurosky Mindwave 和 Websockets

居家办公竟被读取脑电波?老板们为远程监控想出奇招

居家办公竟被读取脑电波?老板们为远程监控想出奇招

UE4 开发之如何创建 iOS 平台插件