Razor项目所感(上)

简单的说下我的Razor四旋翼飞行器项目,还没做完,要暂时搁一搁,就先总结一下。
此项目基于Raspberry Pi上的linux平台进行开发,现仍在开发中。项目地址:
https://github.com/sanwave/Razor

当初设计的功能基本都已实现,主要如下:拍摄照片;获取精确授时并校正系统时间,树莓派掉电后是不保存时间的;记录照片的EXIF信息,主要是地理位置和时间;录取/停止录取视频,这样设计是因为录制视频时不能同时航拍;获取飞行器当前的姿态,使用到陀螺仪、加速度计、电子罗盘和气压计,这方面数据处理还有些问题,不过数据是稳定的,除了气压计的数据还没搞到;开启视频实时监控,通过外置供电USB无线网卡自建WiFi热点和监控主机输出视频流。大概就只有这些。本来是准备拿这货拿来作毕业设计的,不过现在看来可能不太适合。

简单介绍下我的硬件配置:机架用的是小号风火轮,X240,¥95,后面感觉空间确实太小了,无法施展上述全部功能,稍不注意就有可能被桨打到,所以下次做时一定要买个大号的;电调用的是好盈飞腾10A,电机是新西达的A1510,这两件和机架是之前老师挑的,我们觉得还不错,就没有换,共计(50+50)*4;电池买了块好点的,酷点3S 2600mAh 25C,120吧;主控树莓派,外加摄像头,270+220;姿态传感器GY-86模块,80+;GPS模块,80+;USB无线网卡,50+;nRF无线模块,四五块;前面的已经有1300+了,加上其他零零碎碎的至少有1.6k+。做到最后我才发现,树莓派的硬件PWM只有一个,而软件PWM远远不能满足要求,而且跑起来CPU占用率很高,照此情形,势必要再加一块板子了。确实是之前的疏忽,以后再开项目一定要进行严密论证。

软件到目前为止全部基于linux,这样就可以放心的使用C++,较C清爽许多,干净利落,不过Linux下的C++和当初学的C++还有有一点点差别的,因为最开始我用的C,移植过来后IO代码就没有改,继续用着C的stdio库,同时引用C++的iostream库时就要报错,由于不是很必要,我就没有深究下去。当然,要和硬件打交道,还需要专门的硬件开发库,我用的是WiringPi,Gordons开发的一个易用友好的库,仿Arduino风格,上手很简单。芯片提供商Broadcom也提供了bcm2835库,有兴趣可以去下载。

下面细说下各个功能的实现。

 

自建热点

购买无线网卡时只顾着考虑和树莓派的兼容性了,就买了个之前借攀攀用的TP的一款小白,用时才发现构建WiFi Direct没那么简单,资料非常少,而且这款不支持。自建AP热点也只是支持软件模拟AP,在Windows7 下使用竟然要驱动!国内网站上关于树莓派的资料还很少,我只好FQ到外面饱览E文,几经曲折,才成功建成AP热点。具体方法见:http://ncloy.co.uk/blog/?p=593

 

拍摄照片

这个功能实现相对简单,只是要用树莓派的摄像头拍照,必须使用其专用程序,由于官方并未开发GUI程序,所以我们只能用命令行,慢慢就习惯了,而且CUI用程序控制更方便,其丰富的命令行选项为我们提供了大量接口自定义拍摄的照片。比如,我喜欢用暖色,就会指定 "-awb cloud"选项,素描"-style sketch"也很有爱,大家可以试一试。指定EXIF信息可能有些复杂,最好去翻一下EXIF官方文档,参照里面的格式会感觉很清晰。照片的拍摄时间默认使用系统时间,所以只要提前把系统校正就不用再指定EXIF的拍摄时间,GPS位置信息则只能手动指定了。

关于拍照程序,官方文档:http://www.raspberrypi.org/wp-content/uploads/2013/07/RaspiCam-Documentation.pdf  第三方中文翻译:http://dreamcolor.net/2013/05/raspicam-documentation/

 

视频监控

这个功能是之前实现了的。视频监控其实原理很简单,但实现起来有点难度,即不知用何程序去实现,我对linux还不熟,即便是现在的实现也还很不完美。我是用ffmpeg+jwplayer实现的,树莓派官方的程序用于输出视频流,然后ffmpeg将此视频流转为打包为flv格式输出到网络上,再自建站点,php里内建容器把视频流接下来即可。

命令行示例: raspivid -t -0 -hf -vf -awb cloud -w 1280 -h 720 -fps 24 -b 5000000 -o - | ffmpeg -i - -vcodec copy -an -metadata streamName=Razor -f flv tcp://localhost:6666

我还不是很理解其中的参数,尤其是最后一个。

php网页见 https://github.com/sanwave/Razor/blob/master/Others/video.php

至于自建web站点,非常简单,我用的是ngigx,这里不再赘述。

 

视频录制/停止

很惭愧,我最初的初衷是一边输出视频流到网络一边本地录像,但一直没能实现,网络上也没有找到相关资料,虽然原理很简单,就是把管道复制一份出来就ok了。

视频录制很简单,之前介绍树莓派摄像头的文档就有讲解和示例。这里只是提醒一下,视频录下来是x264的文件,用MP4Box打包后才能看。

关于停止,大家会说,实现很简单嘛,直接Ctrl+C就干掉了,但是最后我们用的是程序控制,直接调用shell可以视频录制,却没办法停下来,因为我们不知道那个进程的PID。所以,如果我们要稳定控制视频录制的开始和停止就必须学习如何处理linux下多进程。我的解决方案是:录制视频时,在主进程(控制飞行进程)下fork一新子进程,同时主进程记录下子进程PID,然后子进程exec到shell,调用命令实现视频录制。在这个过程中,shell进程又建立了新的子进程用于执行后面的命令,而在要停止的时候把shell进程kill掉,这样它的子进程就停止工作,摄像头空闲了出来。功能已经实现了,但那个shell进程却没有被彻底干掉,变成僵尸进程,潜伏在系统中,我暂时还没有找到办法干掉他。

 

自建热点

我用的USB无线网卡型号为TL-WN723N,建立模拟AP的官方hostapd程序是不兼容我的那款网卡的,气得我差点想换掉,但其实还是可以用的,只不过需要自行编译hostapd。8188CUS主控建立热点可参考 http://ncloy.co.uk/blog/?p=593  ,配置文件其实也很讲究,我已经上传到GitHub里,有兴趣可以到 https://github.com/sanwave/Razor/blob/master/Others/RasPi_Matrix_Network.txt 查看。

 

姿态传感器

姿态传感器模块GY86包括MPU6050、HMC5883L、MS561101BA三个器件,均使用I2C协议。

我们先来说说linux下的I2C协议程序开发。linux下开发I2C程序最大的优势在于,有一个名叫i2ctools的程序,极大地方便了调试与I2C器件通信的程序,还能扫描线上接入的I2C器件地址,绝对非常好用,吐血力荐。树莓派自带一个硬件I2C接口,不过,这个接口默认是没有开启的,需要手动打开。开启方法详见:http://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup/configuring-i2c 。树莓派上的硬件开发基于WiringPi库,可去 https://projects.drogon.net/raspberry-pi/wiringpi/download-and-install/ 下载安装。

MPU6050采用标准I2C通信,使用起来还是蛮简单的,何况网上驱动一箩筐,论标准,还是推荐I2cdevlib给出的Arduino驱动,我的驱动就是从上面移植下来的,而且此网站还提供了MPU6050及其他I2C器件的寄存器表和讲解,非常具有参考价值,比呆呆地看datasheet要直观清晰的多。
先说一下MPU6050的器件通信,典型通信过程如下,前面为数据内容,后面为寄存器地址:
    1. 0x41 => 0x6B 设定时钟, X轴时钟
    2. 0x00 => 0x1B 陀螺仪量程,250°/s
    3. 0x00 => 0x1C 加速度计量程,2g
    4. 0x01 => 0x6B 唤醒
    5. 0x3B~0x48 观察数据输出,其中,各数据均为2字节长。 0x3B 加速度X, 0x3D 加速度Y, 0x3F 加速度Z, 0x41 温度, 0x43 陀螺仪X, 0x45 陀螺仪Y, 0x47 陀螺仪Z
由于我是用的GY86模块中HMC5883L的数据线接在了MPU6050的从I2C接口上,所以在访问HMC5883L时要先打开MPU6050的bypass模式。HMC5883L的典型通信过程,格式同上:
    1. MPU6050 0x00 => 0x6A 关闭I2C Master 模式
    2. MPU6050 0x02 => 0x37 打开bypass模式
    3. HMC5883 0x70 => 0x00 Config A
    4. HMC5883 0x20 => 0x01 Config B
    5. HMC5883 0x00 => 0x02 连续输出
    6. HMC5883 0x03~0x08 观察数据输出,其中,各数据均为2字节长。注意,0x03为X轴数据,0x05为Z轴数据,0x07为Y轴数据
以上通信过程已经够基本使用,但我还不满足,既然MPU6050可以代劳获取HMC5883L的数据,为什么我不用?这样取数据时更方便,代码实现更优雅。典型设置过程如下:   
    1. 0x20 => 0x6A 打开I2C Master模式
    2. 0x00 => 0x37 关闭bypass模式
    3. 0x0D => 0x24 设置操作从器件的时钟及其他
    4. 0x9e => 0x25 设置从器件的操作模式及其地址
    5. 0x03 => 0x26 设置读取从器件的起始寄存器地址
    6. 0x86 => 0x27 设置读取从器件寄存器的长度及开关等
    7. HMC5883L寄存器0x03~0x08的数据会保存在MPU6050寄存器0x49~0x54中,并周期更新
若以上步骤后MPU6050可能获取不到HMC5883的值,重置一下I2C SLV0试试。我当初就是怎么试都不行,重置了一下,就一直Okay了。

通过以上传感器我们已经可以获得飞行器当前的姿态了,但数据不能直接拿来用的,误差和飘移都太大了,我们要做的工作便是校准和滤波。校准的话,想比大家都会。而滤波,则很有学问了,最好的自然属卡尔曼滤波了,处理后的结果曲线同真实情况吻合的非常好,但这也是最难的吧,计算量也相当可观。有人使用简化版本,但不清楚效果如何,我也没有试过。用的比较多的大概便是互补滤波了,流传较广的Madgwick的AHRS算法便属于这一类,Fabio的FreeIMU项目使用的也是Madgwick的算法,不过修改了个别参数。根据他们的视频,效果还是不错的,但我重现时却发现漂移的厉害,还不知是何原因。
气压计MS561101BA的驱动我还没有搞定,他用的并不是标准I2C,大家可以参考FreeIMU中提供的驱动。

 

GPS通信

GPS通信采用Uart协议,相对简单,不过注意,树莓派的Uart口默认用作命令行调试,需手动关闭,方法详见:https://sites.google.com/site/semilleroadt/raspberry-pi-tutorials/gpio

我买的GPS模块比较烂,u-blox的NEO 6M系列的,搜星能力一般,室内获得授时不是问题,偶尔可以定位。使用Uart 9600时采用NMEA 0183协议V2.3,默认每秒刷新一次i,只能输出7种语句,不过够用了。而我的开发工作只是解析这些语句,表面上看简单无比,但我字符串处理的基本功不够扎实,费了些时日,最后还是用自己实现的字符串分割函数才完成了这一功能,C语言中的strtok不是一般的坑,而且线程不安全,考虑到C的移植我就没有使用C++的string库函数。GPS通信虽然简单,可是要完全消化这些信息却不简单,里面涉及到不同地球物理模型导致的漂移以及各种误差的计算问题,我都没怎么考虑,只是初级使用而已。

 

无线通信

无线模块我们选用了成本极低的nRF24L01,实现近距离无线通信,基本满足要求。相比之下,其他模块性价比太差。
nRF的通信难点仅在SPI通信协议上,搞定了SPI,nRF就差不多了。之前我用TI的LM4F软件模拟SPI就一直没有搞定nRF,反复检查代码,甚至找来同学一起看也没看出道道儿。电赛中被相同的问题绊到后,我才意识到问题所在,初始化操作延时不够,单片机启动延时不够也是一方面。现在,我也只是把代码安上去了,还没有测试,在此也就不多说了。

 

今天就说这么多吧,具体的姿态算法实现和控制算法实现以及上面还没有解决的问题留到下再说。

posted @ 2013-12-12 12:35  Wave San  阅读(1429)  评论(7编辑  收藏  举报