热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

以树莓派为控制中心的软硬件之开发之脑电波模块

脑电波模块:脑电波模块以串口UART相连,提供了有线直连和无线蓝牙两种物理连接方式最初的情况是脑电波模块只有Windows下的调试程序和源代码,而我们使用的是树莓派B+,它的硬件框架是ARM

脑电波模块

脑电波模块以串口UART相连,提供了有线直连和无线蓝牙两种物理连接方式最初的情况是脑电波模块只有Windows下的调试程序和源代码,而我们使用的是树莓派B+,它的硬件框架是ARMv6,因此实际上不不能支持Windows,就连大部分Linux发行版诸如Ubuntn都不支持

开机配置

官方推荐的是Raspbian,这是一个由Debian经过为树莓派优化改进后的版本(%3的软件包经过重新编译)到官网下载系统安装包(实际上是img镜像 )通过Win32DiskImager写入SD卡(在官网上会有一张它所支持的或不支持的SD卡品牌型号,并且考虑到201502版的Raspbian展开有14个G,所有SD卡大小最后不小于32G

操作方式:

  1. HDMI连接接显示器,usb接连线鼠标、键盘 或蓝牙鼠标键盘。注意如果你的显示器没有hdmi接口,只有VGA或DVI时,最后购买带外接电源口的转码线,以防供电不足甚至对树莓派造成破坏
  2. SSH 树莓派默认开启了ssh连接,通过一根网线直连通过路由器UART串口和电脑相连,windows下用PuTTy等远程连接软件连接,并且树莓派安装了tightvnc后,可以用tightvnc 远程开启树莓派图形界面

    默认密码root:pi password: raspberry

适用性修改:

首先是sudo raspi-config 进入配置界面,将整个空间拓展到sd卡全部,修改键盘布局及地区,设置字库spacs 选中

串口操作修改:

  1. 修改 /boot/cmdline.txtcOnsole=ttyAMA0 kgdboc=ttyAMA0两个选项删除,/dev/ttyAMA0 就是UART端口文件
  2. 修改 /etc/inittab 将 最后一行 #T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100 注释掉
    这是因为树莓派的uart串口默认处于调试状态不能直接用

串口编程的小记:

以下是各种比较挫折的经历,实际上折腾这个串口的编程持续到了现在,它的关键实际上就是:
1. 从串口获取数据并成功解析出来
2. 实时获取串口数据,在此基础是实现非堵塞更好

为了实现以上两个目的,作为菜鸟的我从2014年折腾到2015年,冬去春来花落花开一转眼夏天都要到来了。。。
脑电波串口发送的是16进制数据,数据格式听起来很清楚,但仔细一想md,16进制还是10进制还是2进制和我有什么关系,我要的是编码方式!也许这个16进制是某种默认的编码方式但我对那很陌生,一开使尝试 用网线直连树莓派和笔记本ssh远程连接,用线直连脑电波模块串口 并且用 minicom(linux)调试串口,嗯,没什么意义,而且一直收不到目标数据
后来用 TTL串口转usb在Windows下调试,还是收不到数据,也试过TTL串口转usb连树莓派能正常从树莓派向笔记本发送数据,但无法接受数据,这里没有深入研究,之后上网搜了一下串口编程的源码因为我只是对c不谦虚的说比较熟练因此代码只局限于c,结果找出了一大坨的代码,
满屏跑宏,看看就是微醺。在大二下学期的剩余时间里研究c代码,又尝试让树莓派显示中文并输入中文,但尝试很长时间无果,也没有深究。至今疑惑(通过SSH当然可以输入中文)
其实大部分时间还是学习(毕竟是高中一般的西北某高校)和各种强制性的无聊的官方活动 实际上没有做什么有实际效果的事情,到了没有强制性活动 的寒假,花了几天看完了三本Windows注册表的入门级书,又买了本python 学习手册啃啃,啃完了基本数据类型,呵,啃不动了,再加上装电脑什么的就又耽搁了(好吧这其实是借口,前二十天)后二十天又学习了若干部精品Galgame,看了几本小说最后一个周,想起某位操蛋的脸,和我心中残存的良知,我开始重新拾起c的串口源代码,嗯嗯,
其实最麻烦的就是关于串口的控制,各种宏的名字真是抽象,好在本人擅长黑箱编程 总算还是把c串口操作的代码弄好了(期间又浅浅了解了vi/vim,emacs,gcc)整天看着raw字符界面感觉很有逼格233,接着就是
开学。(哎,假期总是太短了。。。)
开学以后,在折腾c,但是自发自收没问题,却无法接收脑电波正确的数据,我看到了穷举式解决问题的思路,颇以为然,然后就开始寻找其他串口通信的方法,听说python是生成快速原型的有力的工具,就找了一下python串口编程(其实就是打开串口,写和读)我擦,居然如此简洁,于是我就抱着试一试的态度分分钟用python重新写了通信的程序,甚至包括windows下的(就那么几行)可是依旧是脑电波模块以外能正常收发数据,而这时候实际上依旧不能通过TTL串口转USB 来调试脑电波模块,通过蓝牙串口的却可以在windows下用官方给定的程序下正确的结束数据,这时候我没有意识到我其实离成功就差一根线
那是后来我的小伙伴小唯 过来关心teammate,我说明了情况,他说向要向 上天祈祷答案,本来没有在意,结果大神给的建议里的一条真的彻底扭转了被动局面(快要中期答辩(同时评定项目等级)了,却还没有东西做出来)建议就是把共地线连上(啥,你说为什么之前连共地线都没有连,哈哈不懂就是这么任性,现在想想如此缺乏电路常识,真是有损我西北某高校的名声)
和脑电波共地以后,接收到的数据也正常了,精神也高涨了,解析个包然后稍微分析一下也是分分钟的事了。但有一点,数据是正确的收到了,但经过分析,全是噪声,根据前次经验,继续向上天祷告,这次大神同样没有令人失望,不但告诉我们用线直连串口对脑电波模块就是干扰大的事实(之前的初步验证是这样的)而且说明了不能用TTL串口转USB的原因
脑电波模块波特率太高(38400应该支持的。。。)不过感谢模电告诉我们的常识,这个理由起码是可以接受的
接下来小伙伴小唯 提出用蓝牙串口代替线连,开始到某宝买了一个,试了几天,发现是坏的。。。,退货,重新买了一个,型号是**CZ-HC-05**CZ-HC-0X系列貌似差不多,嗯,写了这么长时间,是时候贴出源码提升一下逼格了,以下是将蓝牙串口设置为从机模式,而且连接绑定
脑电波模块的蓝牙的过程。

蓝牙串口设置为从机模式,而且连接绑定地址:

    #-*-coding:utf-8-*-
#python 2.7
import serial
import time


ser=serial.Serial('/dev/ttyAMA0','38400')
status=ser.isOpen()
print status

def Transaction(requst,response,ser):
while True:
ser.write(requst)
print 'send:'+requst
n=ser.inWaiting()
response_2=ser.read(n)
print response_2
print len(response_2)
raw_input('press any key to continue')
if response_2==response:
break

#Testing
while True:
ser.write('AT\r\n')
print 'send requst...'
n=ser.inWaiting()
respOnse=ser.read(n)
print response
print len(response)
raw_input('press any key to continue')
if respOnse=='OK\r\n':
break


#set the mode of the Device
while True:
print 'set at the mode of master...'
ser.write('AT+ROLE=1\r\n')
respOnse=ser.read(4)
print response
raw_input('press any key to continue')
if respOnse=='OK\r\n':
break


#Set the mode of query #0--bind mode 1--any 2--loop
print 'Set the mode of query'
Transaction('AT+CMODE=0\r\n','OK\r\n',ser)
#Bind the Addr
print 'Bind the Addr'
Addr='80BA,86,6CE14B'
Transaction('AT+BIND='+Addr+'\r\n','OK\r\n',ser)

#Set the pw
print 'Set the pw'
pw='0000'
Transaction('AT+PSWD='+pw+'\r\n','OK\r\n',ser)

#Set the parameter of the UART # baud,stopbits,cntl #stopbits--0:11:2cntl--0:none 1:odd 2:even
print 'Set the parameter of the UART'
UART='57600,0,0'
Transaction('AT+UART='+UART+'\r\n','OK\r\n',ser)

ser.close()

注释
1. 就像前文说的树莓派的中文显示问题没有搞定,也没时间了,所以 注释全是英文。
2. serial不是2.7的标准库,好在树莓派创建的初因是一台python学习机 ,python装的很全,其实不全也没关系,下载也很方便,利用pip。
3. /dev/ttyAMA0 是树莓派下的串口地址。
4. 其余情况对照 CZ-HC-0X 系列AT 语法易理解

之前忘说了,使用前还要激活,不说了,key 是激活接口,其余网上教程很详细,只是还要注意转为AT模式有两种,二者的波特率不同。

我的树莓派上网之路:

接上蓝牙串口后,噪声神奇的没有了!然后开始寻找眨眼的动作,之前和期间又投入了大量时间解决树莓派的上网问题,最初是可以利用网线直连笔记本,共享笔记本网络的,但后来一次树莓派突然断电(西北某高校晚上断电传统,但那次提前断电了。。。)之后各种折腾包括树莓派重刷系统都无法
连到树莓派,ip找不到,树莓派也上不去网,换了一个笔记本试也是这样,
真是诡异。b+没有无线网卡,我先后买了两个linux下有驱动的无线网卡一个某宝上的,声称有usb接口,结果是有四个孔,kao,自己焊呐,期间犹豫要不要焊的时候又买了某东上的号称专为树莓派准备的免驱动的EUDP无线网卡,但是买回来一看,Linux下免驱都是骗人的(实际我之前傻乎乎的修改了若干遍无线网配置文件,阿西吧果然还是too young吗),EUDP官网上的驱动Linux内核版本,太老了是3.x而201502版的raspbian 的内核版本是3.18 呵呵哒,估计起码这1415两年买的EUDP树莓派要用都得重新编译驱动!

再说说之前那个需要焊USB的无线网卡,虽然我西北某高校盛产焊工,但我委实没有这项手艺和工具,好在拿到某某实验室,好心学长帮焊,又拿502粘了又买了usb延长线,结果发现那个网上适用范围模糊的驱动果然不能用。。。
我也曾(ˇˍˇ) 想~一怒之下学习Linux下的编译。但看了一下教程,嗯
(@ - @)根据以往的经验,再考虑到西北某高校以及新来的某人瞎折腾给我们带来的时间上的压力,学习达到一定效果可能以月记(毕竟完全是小白),而答辩时间上不允许,最后还是滞后了这个问题,毕竟根据会根据源码重新编译很重要,虽然嵌入式方向不太是我的菜。
没办法,还是暂时通过路由器上网吧。

后来小伙伴小唯 去某宝上买了一个1080p树莓派推荐摄像头,号称免驱嗯,还是假的,而且更新了驱动也不能用,坏的,再退货。。。

好了继续谈我的串口编程问题,换上蓝牙串口后一切正常,唯一不正常的是我的程序,太慢了,数据处理的速度,居然赶不上1s的串口数据等待时间。虽然是python但这也太奇葩了吧,这时候无意关注到之前发布的树莓派2
看完就跪了,ARMv7 架构 四核900MHz 1G RAM性能保守估计是B+(单核700MHz、500MRAM)的六倍!而且升级到了ARMv7,这意味着不仅可以支持恐怕是全部的Linux发行版,甚至可以刷WIN10(事实已经有很多人那么干了)而且价格一样几百块搞定233瞬间想起了王菲的那句歌词 为谁辛苦 为谁甜 想起了Aldnoah Zero 那令人无语的结局,想起了某老师毕设是安卓反编译的那年安卓开源了想起了。。。
不过推倒回去显然是不现实的,做下去也挺好,于是乎继续,改进数据处理的时间。很自然的未经测试的我想到这么慢是硬件限制下用python不可避免的结果,然后就想到用C来改写我自以为的拖慢运行时间的部分,实际上我的确是测试了各部分的运行时间,但后来证明我的测试不够准确,因为运行时间和代码量不成正相关,python不同的语句运行时间相差可能不止一两个数量级。接下来我开始了两周的南辕北辙行动。安照
开始考虑多线程,_Thread (python 3.x),Thread(python 2.x),通过
全局锁进行同步,做完了才知道没有用。B+是单核的,而且python的线程无法不是真正的并行。

多线程的意义:

  1. 利用多核优势,并行处理任务提高性能。
  2. 利用cpu片选时间的原理,防止某个长时间运行的任务造成堵塞

**后来
Python Programming 书中推荐的,我写好了c源程序和头文件,然后使用swig 封装产生c的封装文件,最后编写makefile 文件,编译产生动态库和对应的python模块的脚本。

用swig在c中拓展python:

  1. 安装python-dev (-dev类库头文件,调用c/c++ api 必须)
    sudo apt-get install python-dev
  2. 编写c源文件、头文件 将包含要调用的c函数加到头文件里
  3. 为swig 编写 .i 文件方法可查
  4. swig -python -I xxx(c头文件所在目录) xxx.i(之前编写的.i文件)
    生成 模块名_wrap.c (模块名在.i文件开头设置好) 胶水源文件和 模块名.py
    1. gcc -shared 模块名_wrap.c 源文件.c -L xxx(python 库目录) -l xxx(要连接到的库名比如python2.7) -o xxx(Linux .so windows .dll)
      注意:指定生成的动态库名应该为 _模块名.so_模块名.dll
  5. 使用时导入模块名,像普通的python 模块一样使用

用swig在C/C++中拓展python 优点:
1. 不需要手工在C/C++中写大量的粘合部分。
2. 生成对应的模块可以向python模块一样用,使用拓展时是透明的。非指针的值传递一点问题都没有。

缺点:
1. 很难通过指针传递的参数 因此不实用

花了大约一个多周的努力,我认识到直接用swig封装是不靠谱的,因为我需要将传入的参数传回去。
此时我可以选择
1. 手动编写胶水部分的c代码,然后自己修改可以传递指针。
2. 利用python ctypes 库直接调用c api。
我选择了第二项,于是将之前写的.c 源文件直接编译成 .so 动态库

gcc -shared -fPIC -L xxx(头文件目录) -fpermissive xxx.c -o xxx.so` 。

看了一晚上的ctypes英文文档
然后改写竟然分分钟搞定了。然而运行时我发现,调用c优化后的python程序居然比之前还慢!
又尝试将转码部分也用C实现,发现遇到了问题,传过的c_char_p直接转成"%02X" 的16进制格式,格式化成unsigned char* 类型不行
又尝试用c_wchar_p 传 字符串,在下 用swprintf(wchar_t *s,size_t n,const wchar_t * format,...)
%ls 16进制字符串。但依旧不行。
用python很容易实现的转码,c比较麻烦,看到网上有用c++做的,不理解原理,具体的编码还要学习。算了,不管
进一步进行运行时间的测量,发现最耗时的不是我之前所想的那样,是大段的全包搜索模式匹配,而是转码。具体来说就是eval(str) 这条实际上无关紧要的写了只为图方便的语句。。。改掉以后运行时间直接减为原来的2/5
然后文章开头提到的串口编程的两个核心问题解决了。

阶段总结:
  1. 技术有疑惑的时候在自己深入钻研的条件下,别忘了向别人特别是大神求助,帮助你理清思路同时,他们可以指出你思维上的误区或麻痹大意忽略的东西。
  2. 优化程序前一定要先注意精确找到最耗时的部分,起码要确定需要优化的部分耗时比例。然后优化时:
    1. 优先考虑本语言内的优化
    2. 本语言不行,再考虑其他语言
    3. 其他语言可以是C/C++(C++或许比C还要快)
    4. 优先考虑使用ctypes 调用 C API 或自己编写的C/C++库
  3. 人类一思考,上帝就发笑 并且 如果你做一件事一直坚持下去的话,就算老天都会帮你的 (我是拥有辩证唯物史观坚定的无神论者,众神只是规则规律的化身)
    写于2015/5/9 周六 期中考试前夕 ,西北某高校。


推荐阅读
  • MongoDB高可用架构:深入解析Replica Set机制
    MongoDB的高可用架构主要依赖于其Replica Set机制。Replica Set通过多个mongod节点的协同工作,实现了数据的冗余存储和故障自动切换,确保了系统的高可用性和数据的一致性。本文将深入解析Replica Set的工作原理及其在实际应用中的配置和优化方法,帮助读者更好地理解和实施MongoDB的高可用架构。 ... [详细]
  • 本书详细介绍了在最新Linux 4.0内核环境下进行Java与Linux设备驱动开发的全面指南。内容涵盖设备驱动的基本概念、开发环境的搭建、操作系统对设备驱动的影响以及具体开发步骤和技巧。通过丰富的实例和深入的技术解析,帮助读者掌握设备驱动开发的核心技术和最佳实践。 ... [详细]
  • 本文详细介绍了如何在Linux系统中搭建51单片机的开发与编程环境,重点讲解了使用Makefile进行项目管理的方法。首先,文章指导读者安装SDCC(Small Device C Compiler),这是一个专为小型设备设计的C语言编译器,适合用于51单片机的开发。随后,通过具体的实例演示了如何配置Makefile文件,以实现代码的自动化编译与链接过程,从而提高开发效率。此外,还提供了常见问题的解决方案及优化建议,帮助开发者快速上手并解决实际开发中可能遇到的技术难题。 ... [详细]
  • 本文详细介绍了在Ubuntu操作系统中使用GDB调试工具深入分析和调试标准库函数`printf`的源代码过程。通过具体步骤和实例,展示了如何设置断点、查看变量值及跟踪函数调用栈,帮助开发者更好地理解`printf`函数的工作原理及其内部实现细节。 ... [详细]
  • RancherOS 是由 Rancher Labs 开发的一款专为 Docker 设计的轻量级 Linux 发行版,提供了一个全面的 Docker 运行环境。其引导镜像仅 20MB,非常适合在资源受限的环境中部署。本文将详细介绍如何在 ESXi 虚拟化平台上安装和配置 RancherOS,帮助用户快速搭建高效、稳定的容器化应用环境。 ... [详细]
  • 掌握DSP必备的56个核心问题,我已经将其收藏以备不时之需! ... [详细]
  • 本文探讨了将PEBuilder转换为DIBooter.sh的方法,重点介绍了如何将DI工具集成到启动层,实现离线镜像引导安装。通过使用DD命令替代传统的grub-install工具,实现了GRUB的离线安装。此外,还详细解析了bootice工具的工作原理及其在该过程中的应用,确保系统在无网络环境下也能顺利引导和安装。 ... [详细]
  • 在《物联网内核与驱动开发基础课程》第五讲中,详细解析了平台总线技术的应用与开发。本讲内容不仅涵盖了平台总线的基本概念,还深入探讨了其在嵌入式系统中的实现方法及优化策略,为开发者提供了宝贵的实践指导。通过具体案例分析,帮助学员更好地理解平台总线在设备管理、资源分配等方面的关键作用。 ... [详细]
  • 在Ubuntu和Linux Mint系统中安装LibreOffice 6.0的详细步骤
    本文详细介绍了在Ubuntu和Linux Mint操作系统上安装LibreOffice 6.0的具体步骤,包括必要的系统准备、软件源配置以及命令行操作,确保用户能够顺利安装并使用这一开源办公套件。 ... [详细]
  • 在 Debian 11 系统中部署 CMake 的详细步骤与最佳实践
    CMake是一个免费、开源、跨平台的工具系列,旨在构建、测试和打包软件. CMake用于使用简单的平台和独立于编译器的配置文件来控制软件编译过程,并生成可在您选择的编译器环境中使用 ... [详细]
  • 在 Ubuntu 系统上正确安装 NVIDIA 显卡驱动程序前,首先需要卸载已有的驱动版本。这一步骤至关重要,以避免新旧驱动冲突导致系统不稳定。接下来,可以通过官方仓库或 NVIDIA 官方网站下载最新驱动,并使用终端命令进行安装。确保在安装过程中启用适当的内核模块支持,以获得最佳性能和兼容性。此外,建议在安装后重启系统并验证驱动是否成功加载。 ... [详细]
  • 如何在Ubuntu系统中直接使用Snap安装软件
    Canonical与Opera Software近日宣布,基于Chromium的Opera浏览器现已作为Snap包提供给Ubuntu用户,显著提升了在Linux操作系统上的安装便捷性和兼容性。通过Snap,用户可以在Ubuntu系统中轻松安装和更新Opera浏览器,享受更流畅的浏览体验。此外,Snap的容器化特性还确保了应用的安全性和稳定性,为用户提供更加可靠的软件环境。 ... [详细]
  • 利用 JavaScript 实现定时任务的高效执行方法(代码可直接复用) ... [详细]
  • JVM参数设置与命令行工具详解
    JVM参数配置与命令行工具的深入解析旨在优化系统性能,通过合理设置JVM参数,确保在高吞吐量的前提下,有效减少垃圾回收(GC)的频率,进而降低系统停顿时间,提升服务的稳定性和响应速度。此外,本文还将详细介绍常用的JVM命令行工具,帮助开发者更好地监控和调优JVM运行状态。 ... [详细]
  • Windows环境下详细教程:如何搭建Git服务
    Windows环境下详细教程:如何搭建Git服务 ... [详细]
author-avatar
星晴SOS
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有