意念控制四旋翼 学习笔记

2023-11-12

      第一部分:模块原始数据 

      拿到模块,在网上查了一圈,发现基本没什么有用的资料,很多都是一些相关但是没有实际价值的东西。许多论文都是再谈怎么去做,而没有实实在在的去完成这么一个过程。

       废话不多说,直接步入正题。

       

          昨天在网上才发现这个软件,据评论说是这款串口软件很好用。

          RealTerm的下载地址https://realterm.sourceforge.io/       

          这是通过单片机的232通信例程直接接收得到的原始数据,也就是参考手册中的数据流。其中小包数据,是每秒512个大概,大包数据是每秒1个。

       小包的格式是AA AA 04 80 02 xxHigh xxLow xxCheckSum前面的AA AA 04 80 02 是不变的,后三个字节是一只变化的,xxHigh和xxLow组成了原始数据rawdata,xxCheckSum就是校验和。所以一个小包里面只包含了一个对开发者来说有用的数据,那就是rawdata,可以说一个小包就是一个原始数据,大约每秒钟会有512个原始数据。
      从小包中解析出原始数据:

rawdata = (xxHigh << 8) | xxLow;

  if(rawdata > 32768){   rawdata ­=65536;  }

      根据手册,在计算原始数据之前,要先检查检验和:

sum = ((0x80 + 0x02 + xxHigh + xxLow)^ 0xFFFFFFFF) & 0xFF。

     就是把头文件AA AA 04后面的四个数据加起来,取反,在取低八位。当检验码不对时,直接丢弃该包。

     在大包数据里面可以解析Signal,Attention,Meditation和8个EEG的信号值,大包的格式是固定的:

AA 同步
AA 同步
20 是十进制的32,即有32个字节的payload,除掉20本身+两个AA同步+最后校验和
02 代表信号值Signal
C8 信号的值
83 代表EEG Power开始了
18 是十进制的24,说明EEG Power是由24个字节组成的,以下每三个字节为一组
18 Delta 1/3
D4 Delta 2/3
8B Delta 3/3
13 Theta 1/3
D1 Theta 2/3
69 Theta 3/3
02 LowAlpha 1/3
58 LowAlpha 2/3
C1 LowAlpha 3/3
17 HighAlpha 1/3
3B HighAlpha 2/3
DC HighAlpha 3/3
02 LowBeta 1/3
50 LowBeta 2/3
00 LowBeta 3/3
03 HighBeta 1/3
CB HighBeta 2/3
9D HighBeta 3/3
03 LowGamma 1/3
6D LowGamma 2/3
3B LowGamma 3/3
03 MiddleGamma 1/3
7E MiddleGamma 2/3
89 MiddleGamma 3/3
04 代表专注度Attention
00 Attention的值(0到100之间)
05 代表放松度Meditation
00 Meditation的值(0到100之间)
D5 校验和

      想要获得某个EEG信号值,只需将相应信号的1/3值左移16位,2/3值左移8位,3/3值不变,然后将他们或运算:

delta=(payload[i]<<16) | (payload[(i+1)]<<8)  | (payload[(i+2)])。

第二部分:串口接收处理

将数据处理移植到STM32上,采用串口的DMA接收模式,注意的是DMA_MODE采用Circular,DMA_BufferSize>(8*512+36=4132)(小包8个字节,每秒512个,完整的大包36个字节)。

代码如下:

void usart_init()
{
    //声明结构体//
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    
    //时钟打开//
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//DMA1时钟
    
    //GPIO配置//
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    
    //USART配置//
    USART_InitStructure.USART_BaudRate=57600;
    USART_InitStructure.USART_WordLength=USART_WordLength_8b;//传送数据长度
    USART_InitStructure.USART_StopBits=USART_StopBits_1;//停止位长度
    USART_InitStructure.USART_Parity=USART_Parity_No;//校检
    USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流DMA
    USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;//接受发送
    USART_Init(USART1,&USART_InitStructure);
    USART_Cmd(USART1,ENABLE);
}    
 //DMA接收//
    void USART1_DMA_Recv(void)
 {
     
     DMA_InitTypeDef DMA_InitStructure;    
     NVIC_InitTypeDef NVIC_InitStructure;
     
     DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&(USART1->DR);//外设基地址
     DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&buffer;//内存基地址
     DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//SRC作为数据传送的来源
     DMA_InitStructure.DMA_BufferSize=5000;//数据传输长度!!!!!!
     DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不自增
     DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//内存地址自增
     DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//外设数据单位字节
     DMA_InitStructure.DMA_MemoryDataSize=DMA_PeripheralDataSize_Byte;//内出数据单位
     DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//传输模式!!!!!
     DMA_InitStructure.DMA_Priority=DMA_Priority_High;//优先级
     DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//禁止内存到内存传输
     DMA_Init(DMA1_Channel5,&DMA_InitStructure);
     DMA_ClearFlag(DMA1_FLAG_TC5);
     
     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
     NVIC_InitStructure.NVIC_IRQChannel=DMA1_Channel5_IRQn;
     NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
     NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
     NVIC_Init(&NVIC_InitStructure);
     
     DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);//DMA1传送完成产生中断
     USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
     DMA_Cmd(DMA1_Channel5,ENABLE);
    }

      void DMA1_Channel5_IRQHandler(void)//中断函数
{  
     if (DMA_GetITStatus(DMA1_IT_TC5)==1)
         {
        DMA_ClearITPendingBit(DMA1_IT_TC5); 
        DMA_Cmd(DMA1_Channel5, DISABLE);
        flag = 1;  //将下面的程序放到main的while中,不然运行容易丢包
//          for(i=0;i<5000;i++)
//              {
//                    parseByte( buffer[i]);
//              }
//          DMA_Cmd(DMA1_Channel5,ENABLE);
    }
}

这部分代码还需要进一步修改……我们是依靠蓝牙传输信号,在下面会解决如何通信的问题。

下一部分将会讲述当STM3原2接收到始数据后,怎样将它处理后得到signal,attention,meditation和eeg信号的值

第三部分:数据解析

待续……通信协议部分还是比较关键的

第四部分:数据通信

这一部分在我另一篇文章里有示例性的图文介绍

https://blog.csdn.net/seek97/article/details/81333701

我使用的是HC05和BT06俩个蓝牙模块

1、【AT模式】HC05蓝牙模块的PIO11接VCC,上电后即进入HC05AT指令模式,对于BT06蓝牙直接上电进入AT模式,用USBT06转TTL模块连接到电脑的USBT06接口。

2、【打开串口调试助手】开启2个串口调试窗口,一个打开HC05的COM口,一个打开BT06的COM口。【HC05默认波特率一般为38400,BT06默认是9600】.

3、【恢复HC05默认设置】串口调试助手HC05,将HC05恢复默认设置:AT+ORGL【即回车、换行,在串口调试助手上输入一个回车即可】

4、【设置HC05配对码】串口调试助手HC05,配置蓝牙HC05的配对码:AT+PSWD=1234【蓝牙HC05与蓝牙BT06的配对码相同,这样才能成功配对,配对码随意】

5、【设置HC05主模式】串口调试助手HC05,将蓝牙HC05配置为主机模式:AT+ROLE=1

6、【恢复BT06默认设置】串口调试助手BT06,将蓝牙BT06恢复默认设置:AT+ DEFAULT 

7、【设置BT06配对码】串口调试助手BT06,配置蓝牙BT06的配对码与蓝牙HC05一致:AT+PIN 1234

8、【设置BT06从模式】串口调试助手BT06,将蓝牙BT06配置为从机模式:AT+ ROLE

9、【 查询BT06地址 】串口调试助手BT06,查询蓝牙BT06的地址:AT+LADDR    【如20:15:02:12:07:58】

10、【蓝牙HC05绑定蓝牙BT06】串口调试助手HC05,蓝牙HC05绑定蓝牙BT06地址:AT+BIND=0101,01,010101    

【注意把地址的冒号换成逗号,同时注意这个格式,实验多次,只有这样写,HC05才可以绑定该地址】

11、【设置波特率】根据各自的命令符号修改各自的波特率 HC05:AT+UART=57600,0,0。BT06:AT+BAUD7.

12、【常规工作模式】2个模块断电,重新上电后进入常规工作模式,自动完成配对。之后, HC05就能接收到BT06的数据了。

【注意事项】:确保2个蓝牙模块的配对码(PSWD)相同,都上电后两个模块会自动相连。

【设置蓝牙的连接模式】:默认是:0—指定蓝牙地址连接模式,这样HC05才能自动连接绑定的地址,如果不是模式0,设置为模式0:AT+CMODE=0

第五部分:数据处理

待续……这部分会涉及一些算法,比如BP神经网络模型提速特征值

第六部分:系统控制

待续……这部分比较简单,把小四轴的代码理解完成,也就可以实现控制了。

第七部分:论文写作

待续....这部分应该贯穿于整个项目研究过程,注重将学习成果记录

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

意念控制四旋翼 学习笔记 的相关文章

  • torch::jit::load(model_path) 失败原因

    下面是Pytorch配套的视频教程 Pytorch 快速实战教程 0 Pytorch实战前言 哔哩哔哩 bilibili Pytorch 分割实战教程 介绍一个图像分割的网络搭建利器 Segmentation model PyTorch 哔
  • std::vector简介及其使用(转)

    std vector简介及其使用 本文中的vector指的是std vector C 11标准 Vector概述 template
  • 修改组件默认样式之/deep/(less,sass)

    在使用第三方组件时有时候我们想修改组件的样式 可以使用全局的方式 即不使用scoped 如果多处共用我们只需要统一修改 假如有多种类型呢 我们不得不另起一个名字 如果我们想要封装一个组件 定义的样式希望在该文件中生效 不影响其他组件 我们将
  • weex初始的坎坷之路

    年前 老大就交代年后要把某个页面weex实现 当时不了解weex 连名字都叫不出来 问了度娘 才知道跟react native类似的三端开发 春节回来就开始学 入门很坎坷 因为他是以vue为模板引擎 我没学过vue 当时会react 之前也
  • Linux 指令学习之crontab

    crontab简介 crontab可以在指定的时间执行一个shell脚本以及执行一系列Linux命令 运用场景 服务器管理员定时备份数据库数据 服务器管理员定时同步数据库数据 服务器管理员定时备份服务器日志信息 crontab 常用命令 c
  • 基于SpringBoot+MyBatis 五子棋双人对战

    1 核心功能 2 演示效果 3 创建项目 4 数据库设计 5 配置文件 6 用户模块 6 1 登录实现 6 1 1 前后端交互接口 6 1 2 model 层 6 1 3 mapper 层 6 1 4 xml 层 6 1 5 service

随机推荐

  • 谷歌浏览器添加.crx插件

    1 美图 1 下载 crx格式的插件 常用插件网址 http www cnplugins com http chromecj com 2 更改文件后缀名为zip 3 解压zip文件 不可直接双击解压 直接解压可能使解压后的文件不全 使用命令
  • 论文写作的基本套路

    最近在写论文 写好之后给大神师兄看了看 提出了一些意见 按照师兄的意见整理出来 以供以后写作参考 博主是写的英文期刊论文 一 Abstract 一篇论文的精华都在abstract中 一片论文是否能够抓住审稿人的眼球 让审稿人有兴趣读下去 a
  • Vijava (更改虚拟机配置信息(内存、CPU和添加新磁盘)终极版本)

    package com vmware server import java util List import java util Map import org apache log4j FileAppender import org apa
  • 解决idea不显示Services工具栏的问题

    Idea的Services窗口可以展示项目的入口引导类及端口 可以方便的启动及停止相关服务 假如自己的idea里边不显示 可以通过一下方式解决 1 找到自己 idea工作空间的workspace xml文件 2 文件内搜索 RunDashb
  • vue项目中封装手动上传多个图片并支持修改和移除

    现有的组件库无法满足手动上传文件到服务器 并支持通过按钮修改和移除文件的操作 所以我利用原生input进行封装 如有需要请拿走 1 页面部分 div class container div class upload picture div
  • centos7 查看服务器配置信息

    1 linux查看版本当前操作系统发行信息 cat etc centos release cat etc centos release 2 查看内核版本uname a或者cat proc version 3 查看CPU参数 1 查看 CPU
  • uniapp 本地缓存剩余时间

    封装代码 在项目根目录项新建 utils 文件夹 再新建一个 idea js 文件 import store from store js module exports 计算剩余时间 timeRemaining val time return
  • 二叉搜索树-AVL树的实现

    首先 AVL树是一棵加了额外平衡条件的搜索树 这是因为普通的搜索树如果插入的key接近有序的话 二叉树将会退化成一个单链表 导致查找的时间复杂度为O N 而AVL树中用一个平衡因子来制约树的左右子树的高度 保证任何节点的左右子树高度之差最多
  • Android开发人员应该选择哪种语言?

    自 Google 于 2017 年宣布 Kotlin 成为 Google IO 的 Android 开发官方语言以来 想要成为Android开发人员的程序员正陷入两难境地 在讨论这个问题前 我首先要明确一点 不要陷入编程语言战争 不要进行语
  • 【亲测解决】AttributeError: module ‘tensorflow‘ has no attribute ‘__version__‘

    今天在安装使用bert as service时报错 报错信息如下 AttributeError module tensorflow has no attribute version 一看 懵逼了 啥 tensorflow么有 version
  • centos 内核升级

    首先查看centos版本 cat etc centos release 或者 rpm q centos release 查看内核版本 uname sr 查看官方内核 https www kernel org 接下来升级内核 大多数现代发行版
  • 太牛叉了!解决“卡脖子”的国产自主 IDE [狗头.jpg]

    推荐关注 综合整理 程序员的那些事 ID iProgrammer 解决 卡脖子 的自主创新 IDE 最近有一个的国产自主创新的 CEC IDE 震动了程序员圈子 在 CEC IDE 官网简介中的 安全可控 条目自称 国企品牌 自主研发 注意
  • k8s运维 pod、node、namespace、pv处于terminating的原因及处理方法

    1 概述 node pod ns pv由于一些原因在生产中处于terminating的状态 常规方法无法删除 一下总结了一些原因以及删除方法 2 node处于Terminating状态原因及处理方法 node节点不可达的情况下 kubect
  • MATLAB嵌套循环求解1到1000的素数和

    熬夜打卡 代码都跑过一遍的 没有任何问题啦 方法一 matlab的嵌套循环 重在理解 clc clear s 0 for i 2 1000 for j 2 32 if mod i j break end end if j gt i j s
  • 【华为OD机试】阿里巴巴找黄金宝箱(IV)(C++ Python Java)2023 B卷

    时间限制 C C 1秒 其他语言 2秒 空间限制 C C 262144K 其他语言524288K 64bit IO Format lld 题目描述 一贫如洗的樵夫阿里巴巴在去砍柴的路上 无意中发现了强盗集团的藏宝地 藏宝地有编号从0 N的箱
  • 常用的BOM属性 - Kaiqisan

    终于出狱了 今天重新恢复博客的更新 大致谈谈我复习面试上面的查漏补缺的内容 首先讲讲什么是BOM BOM简单来说就是浏览器对象 只有js在浏览器环境运行时才会被赋予的对象 location对象 该对象内所有的属性都与URL有关 常常用于提取
  • 攻防世界————fileclude(内含php伪协议菜鸟讲解)

    先进去发现为一坨php代码 新手勉勉强强看得懂 接下来我们分析代码 WRONG WAY
  • Angular2-使用Augury来调试Angular2程序

    原文链接 http www jianshu com p efecaea287f2 推荐 Augury Angular专用的chrome 调试插件 如题 就在前几天的2016 12 8谷歌开发者大会上 angular2的leader来给我们演
  • idea字体主题集合

    http color themes com view index
  • 意念控制四旋翼 学习笔记

    第一部分 模块原始数据 拿到模块 在网上查了一圈 发现基本没什么有用的资料 很多都是一些相关但是没有实际价值的东西 许多论文都是再谈怎么去做 而没有实实在在的去完成这么一个过程 废话不多说 直接步入正题 昨天在网上才发现这个软件 据评论说是