在阅读本文之前,请确保你已经阅读过我的另外几篇关于Pi的文章,因为本文与它们有或多或少的关系。
Before reading this article, please make sure that you've read some other articles of mine on Pi, because this article is more or less based on them.
【1】本文主要内容 / Main content of this article
构建一个具有旋转自由度的远程监控系统,使用微信(WeChat)向树莓派发送指令,再由树莓派直接控制步进电机带动摄像头旋转、拍照,并将照片回传到微信上。
将这样一套设备放在某个地方,就可以通过微信监控其周围的情况了。
先看演示效果(收到了从微信发送的指令之后,摄像头就转动了):
视频地址:http://player.youku.com/player.php/sid/XNjg1NzQ5NzM2/v.swf
【2】实现方案 / The implementation
用下图表示:
最上方是用户,你就是你所处的位置。通过微信,用户添加了一个公众账号之后,可以向其发送消息。微信Server(腾讯的服务器)收到消息之后,会根据你在微信公众账号后台的设置,决定是直接回复这条消息(以固定内容),还是将其转发到另一台你自己指定的服务器上。显然,由于有树莓派的存在,我们必须要有另一台服务器(图中的“Web Server”)的存在,因为我们不可能将树莓派挂在微信Server上。
有了那台“Web Server”,Pi就可以与之通信,间接地收到来自微信Server(其实也就是用户)的指令了。收到指令后,Pi会执行它,要么拍照,要么控制步进电机带动摄像头转动。
有人会说,为什么我们不能让微信Server直接与Pi交互?例如,我在Pi上架设一个Web Server,微信Server就可以直接和它通信了啊!
没错,但是这样的条件要求太高了。这是因为:
1)微信Server不接受任何服务器主动向它发送请求,只能是微信Server向其他服务器发送请求,其他服务器再回复;
2)在中国的网络环境下,一个家庭宽带里接入的设备,通常都是没有公网IP的。如果你非要通过配置端口映射等方法来让外面的服务器可以直接访问到家里的服务器的话,配置太麻烦。
文章来源:http://www.codelast.com/
【3】中转服务器的角色
中转服务器即图中的“Web Server”,它负责与微信Server交互、与Pi交互,将来自微信的指令转达到Pi那里,接收来自Pi的数据,等等。
之所以叫它“Web Server”,是因为运行在其上的,是一个web应用程序。
有人说,我自己从来都没有一台具有公网IP的服务器,怎么搭建这样一个web应用?不用急,有大量免费的互联网资源可以用!例如Google App Engine(GAE),Sina App Engine(SAE),Baidu App Engine(BAE),等等。
这些*AE是什么东西?它们的学名可以统称为“公有云计算平台”,用人话说就是“为你提供一台虚拟服务器,可以在上面搭建web应用程序”。
GAE在国内被墙了,SAE和BAE是仿GAE搞起来的,SAE比BAE先出世,于是我选了SAE。
SAE支持在上面用Python、PHP、Java来开发web应用,像我开发的这个应用,SAE的免费配额够用好久了。
另外我要提的是,SAE只是在最近,才开放了一个实时服务——Channel。这个东西是个什么概念?你在SAE上的程序是不支持bind()的,也就是你不能写一个程序监听某个特定端口,来实现一个服务,SAE出于安全性考虑才做了这种限制。为了弥补这种缺陷,SAE推出了一种名为Channel的服务:
“Channel是SAE提供的实时消息推送服务。通过在浏览器和SAE服务端之间建立长连接,使得应用可以方便的向Javascript客户端实时的推送消息。开发者可以利用Channel服务开发自己的实时性要求比较高的应用,如游戏、在线聊天室、在线直播等。”
但是如果我没记错的话,它的文档中写过,最好不要通过Channel服务传送超过4K的数据——这就有点弱了,要知道,摄像头拍摄的一张照片几乎是必须要超过4K的,所以,按我的理解,想通过SAE Channel服务来实时化中转服务器和Pi之间的交互,还是不现实的。
因此,我干脆就把中转服务器弄得简单一点,不去想完全实时化的情景,而是在收到微信Server发来的指令后,存储在MySQL中,由Pi周期性轮循中转服务器来获取指令。
【4】微信Server是怎么将用户指令发到中转服务器上的
首先你要创建一个微信公众账号,并申请成为一名微信开发者。然后,你在微信中查找并添加这个公众账号,就可以向它发送文本消息(即本文所说的指令)了。这个消息其实是发送到了微信Server上,至于微信Server是将该消息转发出去,还是直接以固定内容回复,这是由你在微信公众平台的后台设置的。在我的这个项目中,当然是让微信Server发送到我的中转服务器去处理,按微信Server的要求,必须要在5秒内给它回复(否则就无效了)。
我个人觉得,微信的开发文档写得不好,有些至关重要的东西说得不明不白,很多人在微信开发者论坛中发帖问,才找到了答案。例如,一个“订阅号”是没有权限将图片之类的素材上传到微信Server上的,只有“服务号才行,但是对我这样的个人来说,申请到“服务号”是完全不可能的事情,这就决定了我的技术方案要适应它——我不能把Pi拍摄的照片发送到微信Server上,而只能放在中转服务器(SAE)上,只回传图片的public URL给微信。这也就导致了本系统的安全性得不到保证——一个用户控制自己的Pi拍摄的照片,不应该可以在公网上被检索到。虽然SAE可以限制指定域名才能访问其Storage中的文件,但是我觉得这样安全性仍然不够。
无论如何,在Hackathon比赛时间有限,我无法完善这个系统,能让它按设想的“动起来”,我就心满意足了。
【5】Pi控制步进电机以及摄像头拍照
Pi控制摄像头拍照最终使用了V4L2来实现(具体可以看这里),在Hackathon的过程中,我为了拍照程序不稳定的头疼问题折腾了一个多小时,最终达到了一个“可接受”的结果。
至于Pi如何控制步进电机,这里也不详述了。
【6】系统物理结构搭建
这里说的物理结构搭建,是指我怎样把上面林林总总的各种东西用一个外壳包装起来?
先看成品的实拍图:
近距离,仔细看摄像头和步进电机的连接方式:
俯视图:
你一下就明白了:这不是用乐高积木搭建起来的嘛!
准确地说,是用山寨的乐高积木搭建起来的。淘宝上买的仿乐高货,积木个头很大一块,可以把树莓派、步进电机驱动板、步进电机很好地固定在中间,动弹不得,并且拆卸方便,对于一个实验性的系统来说,堪称完美包装器材。
仔细看中间那张图,步进电机和摄像头是怎么连接在一起的?看起来简单,其实它是我花费了相当大的功夫,以损失了相当大的身体健康为代价才做出来的:
首先,摄像头买来的时候有一个比较大的底座(市面上的非特殊定制的摄像头都差不多吧),由于两块“乐高”积木中间的空间容不下那么大的底座(并且底座也不是平的,会影响转动),所以必须要切割底座。切割是个痛苦的过程,电锯与塑料高速摩擦产生了很多有毒气体,味道很臭,我戴着PM 2.5的口罩仍然感觉无防护作用(真应该把3M的活性炭防毒面具带过去的)。
但这只是第一步!
就算切割好了摄像头的底座,要把它粘贴到步进电机上那根细细的转轴上,也不是件容易的事情。为了让这个粘贴更牢靠,我的设计是:先切割一块圆的小亚克力板出来,中间钻个洞,刚好有电机轴那么大,然后先把这块小圆板固定、粘贴到电机转轴上,最后再把摄像头底座粘贴到这块亚克力板上。
事实证明这样的设计粗陋却非常有效,最后摄像头被牢牢地固定在了步进电机上,并且不影响转动。
【7】总结
Hackathon是一种精神,或许我做的东西和牛人们的发明相比什么也不算,或许我做的东西和很多科技产品相比简陋无比,但是,它毕竟是我一点一滴做出来的,它的每根导线、每个流动的字节之间都流淌着我的血液,看到它出生的那一刻,那种激动的感觉无法形容!
这也是我热爱技术的原因之一——尽管我渺小,但是它却给了我想像发挥的空间,每个人都能在它里面找到自己的位置。