神念TGAM模块+树莓派GPIO控制灯泡(脑电波控制物联网应用示例)

前言

接触TGAM脑电波模块是在年初的时候。刚好临近毕业,指导老师找到了我,想让我加入他负责的毕业课题。在此之前有用过Tensorflow做过一个菜品识别的小程序,当时第一步的构思就是收集大量的脑电波数据,用TF训练机器学习模型,但是后来因为考HCIE跟公司项目的事情耽搁了几个月,又临近了毕业答辩,就只是简单的利用了TGAM模块收集到的专注值跟放松值对灯泡进行了一个简单的控制。

前期准备

网上收集TGAM模块的资料

网上介绍TGAM的模块的资料实在是太少了,找了挺久的,找到了一个“基于神念TGAM的脑波小车”的项目,链接如下:https://www.cnblogs.com/fangyuanjili/archive/2018/04/01/8687844.html 。这个项目对TGAM模块发送过来的包的讲解非常的详细。接下来就是进行解包操作,还是由于时间问题,解包的步骤是参考这个老哥的,链接如下:https://blog.csdn.net/y786256773/article/details/80167900

了解蓝牙

刚好公司的上一个项目是一个蓝牙控制器的小程序,手里有一些蓝牙模块,了解了一下蓝牙的工作原理。主要是手贱,把模块给弄坏了,用某宝的物品识别竟然找到了相同型号的SPP模块,艰难的手动焊了一个上去,完美修复。(滑稽)

ps:接收端是用的千月的蓝牙适配器(有点想吐槽)

项目架构

理想级架构

理想架构

现实级架构

不放了,放了丢人

代码讲解

整个项目分:脑电波接收端、树莓派控制端.

脑电波接收端

脑电波接收端用了pyqtgraph库,用于显示脑波数据跟专注值/放松值

//数据显示
class ShowThread(threading.Thread):
    def __init__(self, parent=None):
        super(ShowThread, self).__init__(parent)
        self.is_started = threading.Event()
        self.win = pg.GraphicsWindow(title="脑电波")
        self.win.resize(1000, 600)
        self.win.setWindowTitle('脑电波检测值')
        pg.setConfigOptions(antialias=True)
        self.p2 = self.win.addPlot(title="专注值(蓝色)/放松值(绿色)")

        self.p6 = self.win.addPlot(title="脑电波值")
        self.curve = self.p6.plot(pen='y')
        self.curve2 = self.p2.plot(pen=(0, 255, 0), name="放松值")
        self.curve3 = self.p2.plot(pen=(0, 0, 255), name="专注值")


        self.ptr = 0
        self.ptr2 = 0
    def run(self):
        while True:
            self.curve.setData(data)
            self.curve2.setData(data2)
            self.curve3.setData(data3)
            self.is_started.wait(timeout=0.2)
//接收eeg数据
class EEGThread(threading.Thread):

    def __init__(self, parent=None):
        super(EEGThread, self).__init__(parent)
        self.ip = "http://192.168.43.10"
        self.com = "COM9"
        self.bps = 57600
        self.vaul = []
        self.is_open = False
        self.is_close = True
    def checkList(self,list,num):
        list_num = 0
        for i in list:
            if i > num:
                list_num += 1
        return list_num

	//检测接收的eeg信号包中的delta值是否持续大于200,此方法是我写的一个粗糙的检测眨眼等生物电流的算法,当监测到之后执行关灯操作
    def checkEeg(self):
        old_num = 0
        delta_num = 0
        for old in old_data:
            if self.checkList(old,200)>5:
                old_num += 1

        delta_num =self.checkList(delta_data, 50000)

        if old_num > 3 and delta_num > 4:
            return True
        else:
            return False


    def run(self):
        global data,data2,data3,old_data,delta_data
        try:

            t = serial.Serial(self.com, self.bps)
            b = t.read(3)
            requests.get(self.ip + "/gpio", params={"oper": "startr"})
            print(str(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))+"脑电波设备配对中")
            while b[0] != 170 or b[1] != 170 \
                    or b[2] != 4:
                b = t.read(3)

            if b[0] == b[1] == 170 and b[2] == 4:
                print(str(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))+"配对成功。")
                requests.get(self.ip+"/gpio", params={"oper": "startb"})
                a = b + t.read(5)

                if a[0] == 170 and a[1] == 170 and a[2] == 4 and a[3] == 128 and a[4] == 2:
                    while 1:
                        try:

                            a = t.read(8)
                            sum = ((0x80 + 0x02 + a[5] + a[6]) ^ 0xffffffff) & 0xff
                            if a[0] == a[1] == 170 and a[2] == 32:
                                y = 1
                            else:
                                y = 0
                            if a[0] == 170 and a[1] == 170 and a[2] == 4 and a[3] == 128 and a[4] == 2:
                                p = 1
                            else:
                                p = 0
                            if sum != a[7] and y != 1 and p != 1:
                                b = t.read(3)
                                c = b[0]
                                d = b[1]
                                e = b[2]
                                while c != 170 or d != 170 or e != 4:
                                    c = d
                                    d = e
                                    e = t.read()

                                    if c == (b'\xaa' or 170) and d == (b'\xaa' or 170) and e == b'\x04':
                                        g = t.read(5)
                                        if c == b'\xaa' and d == b'\xaa' and e == b'\x04' and g[0] == 128 and g[1] == 2:
                                            a = t.read(8)
                                            break

                            if a[0] == 170 and a[1] == 170 and a[2] == 4 and a[3] == 128 and a[4] == 2:

                                high = a[5]
                                low = a[6]
                                rawdata = (high << 8) | low
                                if rawdata > 32768:
                                    rawdata = rawdata - 65536
                                sum = ((0x80 + 0x02 + high + low) ^ 0xffffffff) & 0xff
                                if sum == a[7]:
                                    self.vaul.append(rawdata)
                                if sum != a[7]:
                                    b = t.read(3)
                                    c = b[0]
                                    d = b[1]
                                    e = b[2]
                                    while c != 170 or d != 170 or e != 4:
                                        c = d
                                        d = e
                                        e = t.read()
                                        if c == b'\xaa' and d == b'\xaa' and e == b'\x04':
                                            g = t.read(5)
                                            if c == b'\xaa' and d == b'\xaa' and e == b'\x04' and g[0] == 128 and g[
                                                1] == 2:
                                                a = t.read(8)
                                                break
                            if a[0] == a[1] == 170 and a[2] == 32:
                                c = a + t.read(28)
                                delta = (c[7] << 16) | (c[8] << 8) | (c[9])
                                # print(delta)

                                data = self.vaul

                                old_data.append(data)
                                if len(old_data) > 10:
                                    old_data = old_data[-10:]

                                delta_data.append(delta)
                                if len(delta_data) > 10:
                                    delta_data = delta_data[-10:]

                                flag = self.checkEeg()
                                data2.append(c[32])

                                if len(data2) > 20:
                                    data2 = data2[-20:]

                                data3.append(c[34])

                                if len(data3) > 20:
                                    data3 = data3[-20:]

                                if self.is_open and flag and not self.is_close:
                                    print(str(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))+"关闭灯成功")
                                    requests.get(self.ip+"/gpio", params={"oper": "stopall"})
                                    # requests.get(self.ip + "/gpio", params={"oper": "startr"})
                                    self.is_close = True
                                    self.is_open = False

                                if c[32] > 70 and not self.is_open and self.is_close and not flag:
                                    print(str(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))+"开启灯成功")
                                    requests.get(self.ip+"/gpio", params={"oper": "startg"})
                                    requests.get(self.ip+"/gpio", params={"oper": "start"})
                                    self.is_open = True
                                    self.is_close = False

                                self.vaul = []
                        except Exception as e:
                            # print(e)
                            sse =1

        except Exception as e:
            # print(e)
            sse = 1

树莓派控制端

树莓派利用GPIO串口对led灯进行开关操作,led灯泡一头接gnd,一头接入程序设定的串口上,这里我做了指示灯跟照明灯,使用flask框架向外提供url接口

//flask设置的路由
api.add_resource(GPIORoute, '/gpio')
class GPIORoute(Resource):
    def get(self):
        try:
            self.parser = reqparse.RequestParser()
            self.parser.add_argument('oper', type=str, help='status: type is str')
            self.args = self.parser.parse_args()
            self.oper = self.args['oper']
            if self.oper == "start":
                gpio.jox_start("LED")
            elif self.oper == "stop":
                gpio.jox_stop("LED")
            elif self.oper == "startr":
                oper=""
                gpio.jox_start("RED")
            elif self.oper == "startg":
                gpio.jox_start("GREEN")
            elif self.oper == "startb":
                gpio.jox_start("BULE")
            elif self.oper == "stoprgb":
                gpio.jox_stop("RGB")
            elif self.oper == "stopall":
                gpio.jox_stop("LED")
                gpio.jox_start("RED")
            elif self.oper == "exit":
                gpio.jox_exit()

        except Exception as e:
            print(e)
            return "erro"


//控制GPIO串口的线程类,这里使用的是131926串口
class GPIO(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.LED = 15
        self.SLEDR,self.SLEDG,self.SLEDB =13,19,26
        RPi.GPIO.setmode(RPi.GPIO.BCM)
        RPi.GPIO.setup(self.LED, RPi.GPIO.OUT)
        self.pwm = RPi.GPIO.PWM(self.LED, 70)
        self.pwm.start(0)
        RPi.GPIO.setup(self.SLEDR, RPi.GPIO.OUT)
        RPi.GPIO.setup(self.SLEDG, RPi.GPIO.OUT)
        RPi.GPIO.setup(self.SLEDB, RPi.GPIO.OUT)

        self.pwmR = RPi.GPIO.PWM(self.SLEDR, 70)
        self.pwmG = RPi.GPIO.PWM(self.SLEDG, 70)
        self.pwmB = RPi.GPIO.PWM(self.SLEDB, 70)
        self.pwmR.start(0)
        self.pwmG.start(0)
        self.pwmB.start(0)

    def jox_start(self,jox_type):
        print(jox_type+":start")
        try:  
            if jox_type == "LED":
                self.led_exit = Event()
                self.pwm.ChangeDutyCycle(100)
            elif jox_type == "RED":
                self.pwmR.ChangeDutyCycle(100)
                self.pwmG.ChangeDutyCycle(0)
                self.pwmB.ChangeDutyCycle(0)
            elif jox_type == "GREEN":
                self.pwmR.ChangeDutyCycle(0)
                self.pwmG.ChangeDutyCycle(100)
                self.pwmB.ChangeDutyCycle(0)

            elif jox_type == "BULE":
                self.pwmR.ChangeDutyCycle(0)
                self.pwmG.ChangeDutyCycle(0)
                self.pwmB.ChangeDutyCycle(100)
        
        except Exception as e:
            print(e)
            
    def jox_stop(self,jox_type):
        print(jox_type+":stop")
        try:
            if jox_type == "LED":
                self.pwm.ChangeDutyCycle(0)
            elif jox_type =="RGB":
                self.pwmR.ChangeDutyCycle(0)
                self.pwmG.ChangeDutyCycle(0)
                self.pwmB.ChangeDutyCycle(0)
        except Exception as e:
            print(e)

    def jox_exit(self):
        try:
            RPi.GPIO.cleanup()
        except Exception as e:
            print(e)

结尾

写得有点菜,欢迎各位大佬指正,github地址:https://github.com/jon-son/jox-egg

  • 8
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值