树莓派用服务方式设置开机启动

最近有个项目利用树莓派来完成,主要是在树莓派上用python写了个脚本来处理一些信息与逻辑。这边就遇到一个问题,即设置该脚本在开机的时候自动运行,而不是需要人登陆到树莓派上在执行这个程序,这样太麻烦了,顶多在实验室玩玩,拿不出去。本文主要讲诉设置该python脚本在树莓派上自动运行。

一、首先写个简单的python 脚本

脚本很简单,就是树莓派上一个灯闪烁程序,需要学gpio可以看我之前的博客

文件保存在/home/pi/script/ledblink.py

#!/usr/bin/env python import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) GPIO.setup(21,GPIO.OUT) while True: try: GPIO.output(21,True) time.sleep(1) GPIO.output(21,False) time.sleep(1) except (KeyboardInterrupt, SystemExit): GPIO.close() print “exit”

二 开机启动脚本

保存脚本为/etc/init.d/ledblink文件

#!/bin/bash # /etc/init.d/ledblink ### BEGIN INIT INFO # Provides: embbnux # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: ledblink initscript # Description: This service is used to manage a led ### END INIT INFO case “$1” in start) echo “Starting LED Blink” /home/pi/script/ledblink.py & ;; stop) echo “Stopping ledblink” #killall ledblink.py kill $(ps aux | grep -m 1 ‘python /home/pi/script/ledblink.py’ | awk ‘{ print $2 }’) ;; *) echo “Usage: service ledblink start|stop” exit 1 ;; esac exit 0

三 设置python脚本开机启动

sudo chmod +x /etc/init.d/ledblink

这样启动改脚本用service 命令就可以

sudo service ledblink start#启动 sudo service ledblink stop#停止

最后设置开机启动就好了

sudo update-rc.d ledblink defaults

这样就完工了,重启树莓派就会发现led自己闪烁了,停止用sudo service ledblink stop就行。

参考: Run a script on start up

原文链接

树莓派官方宣布与Coder Dojo合并

树莓派(Raspberry Pi)官方近日宣布与Coder Dojo合并,打算做全球最大的促进编程组织,其目的是汇集资源和专业知识,推进青少年编程教育,让更多青少年可以得到编程培训服务。

树莓派目前是全球第三大计算机平台,从推出之时凭借价格便宜,高定制化和可玩性的特点吸引着人。这也不是树莓派第一次进行合并,早在2015年11月已经和英国的Code Club合作过。而Coder Dojo于2011年创办于爱尔兰都柏林,这是一个专注于帮助7至17岁青少年学习编程的组织,目前其在69个国家中有1250多名志愿者,为35000多名儿童和青少年服务,双方计划是在2020年底前将志愿者增加四倍,达到5000名左右。

树莓派基金会将作为独立的慈善机构,提供资源以帮助支持教授编程服务的Coder Dojo志愿者。并且还运行编程俱乐部网络,为超过15万名儿童提供服务。此外该组织表示将更多地关注软件,提升其慈善工作。

树莓派GPIO入门:GPIO控制RGB彩色LED灯

之前我们学会如何通过PWM来控制LED的亮度,这次我们还是利用PWM来控制一个RGB彩色LED灯来显示各种我们想要的颜色。

最终效果

硬件

彩色RGB二极管。我用的是淘宝买的带4根引脚的S801。你也可以用别的原理都是一样的。

杜邦线4条。3根连接红色绿色蓝色,还有一根连接树莓派5V电源引脚。

原理说明

这个RGB彩色LED里其实有3个灯,分别是红灯绿灯和蓝灯。控制这三个灯分别发出不同强度的光,混合起来就能发出各种颜色的光了。 LED灯上的4根引脚分别是VCC,R,G,B。 VCC需要接到电源正极。我们把它连到树莓派的5V引脚上。 R,G,B分别是红绿蓝灯的负极接口。我们把它们连接到树莓派的GPIO口上。 然后跟前一篇一样,使用PWM来控制3个小灯的明暗程度即可混合出各种不同颜色的光。

硬件连接

#!/usr/bin/env python # encoding: utf-8 import RPi.GPIO import time R,G,B=15,18,14 RPi.GPIO.setmode(RPi.GPIO.BCM) RPi.GPIO.setup(R, RPi.GPIO.OUT) RPi.GPIO.setup(G, RPi.GPIO.OUT) RPi.GPIO.setup(B, RPi.GPIO.OUT) pwmR = RPi.GPIO.PWM(R, 70) pwmG = RPi.GPIO.PWM(G, 70) pwmB = RPi.GPIO.PWM(B, 70) pwmR.start(0) pwmG.start(0) pwmB.start(0) try: t = 0.4 while True: # 红色灯全亮,蓝灯,绿灯全暗(红色) pwmR.ChangeDutyCycle(0) pwmG.ChangeDutyCycle(100) pwmB.ChangeDutyCycle(100) time.sleep(t) # 绿色灯全亮,红灯,蓝灯全暗(绿色) pwmR.ChangeDutyCycle(100) pwmG.ChangeDutyCycle(0) pwmB.ChangeDutyCycle(100) time.sleep(t) # 蓝色灯全亮,红灯,绿灯全暗(蓝色) pwmR.ChangeDutyCycle(100) pwmG.ChangeDutyCycle(100) pwmB.ChangeDutyCycle(0) time.sleep(t) # 红灯,绿灯全亮,蓝灯全暗(黄色) pwmR.ChangeDutyCycle(0) pwmG.ChangeDutyCycle(0) pwmB.ChangeDutyCycle(100) time.sleep(t) # 红灯,蓝灯全亮,绿灯全暗(洋红色) pwmR.ChangeDutyCycle(0) pwmG.ChangeDutyCycle(100) pwmB.ChangeDutyCycle(0) time.sleep(t) # 绿灯,蓝灯全亮,红灯全暗(青色) pwmR.ChangeDutyCycle(100) pwmG.ChangeDutyCycle(0) pwmB.ChangeDutyCycle(0) time.sleep(t) # 红灯,绿灯,蓝灯全亮(白色) pwmR.ChangeDutyCycle(0) pwmG.ChangeDutyCycle(0) pwmB.ChangeDutyCycle(0) time.sleep(t) # 调整红绿蓝LED的各个颜色的亮度组合出各种颜色 for r in xrange (0, 101, 20): pwmR.ChangeDutyCycle(r) for g in xrange (0, 101, 20): pwmG.ChangeDutyCycle(g) for b in xrange (0, 101, 20): pwmB.ChangeDutyCycle(b) time.sleep(0.01) except KeyboardInterrupt: pass pwmR.stop() pwmG.stop() pwmB.stop() RPi.GPIO.cleanup()

原文链接 http://blog.mangolovecarrot.net/2015/04/29/raspi-study03/,版权属于:芒果爱吃胡萝卜。

用树莓派在B站24小时直播音乐

感谢IT之家网友 晨旭喵 的投稿

为何要用树莓直播?

因为我的树莓基本在吃灰,而且它运行起来省电,直播放音乐什么的又完全能够胜任,所以它就被我硬点来当作直播的主机了

需要注意的事项:

天气较热,树莓如果打开了超频,请装散热风扇。建议不开超频

最终效果:

点击这里(不保证我以后不改直播内容哈)

下面是正文~

第一步:安装ffmpeg和解码器

先安装解码器(注意要一句一句执行……)

sudo git clone git://git.videolan.org/x264 cd x264 ./configure –host=arm-unknown-linux-gnueabi –enable-static –disable-opencl make sudo make install cd .. rm -rf x264

再安装ffmpeg(一句一句执行……)

sudo git clone git://source.ffmpeg.org/ffmpeg.git cd ffmpeg sudo ./configure –arch=armel –target-os=linux –enable-gpl –enable-libx264 –enable-nonfree make sudo make install cd .. rm -rf ffmpeg

有两个地方需要注意:

1、git下载慢的话可以先导入到gitosc再clone;

2、编译ffmpeg的过程在树莓上十分漫长。。。我的花了两个半小时,所以建议使用screen扔到后台,以免断网导致需要重来。

第二步:准备直播所需要的视频文件

我们需要制作一个只有背景音乐的视频,一般会做一个一图流的视频(整个视频画面就是一张图),

这里我使用了小丸工具箱(点我下载),

先要合并一堆mp3文件,具体方法:

全选这些mp3文件;

右击添加到压缩文件;

文件类型选择zip,压缩类型选择“储存”;

将压缩好的xxx.zip拓展名改为. mp3即可(是不是很神奇hhhhh)。

接下来照一张图片,打开小丸工具箱,选择“常用”选项卡;

把图片拖到“一图流”的“图片”框里,把整合好的音乐拖到“音频”框里,点击“压制”(水印是我自己打的哈哈哈哈);

这样我们就得到了我们需要的文件。

第三步:进行推流

把文件传到树莓上,使用下面的命令即可推流:

ffmpeg -re -i “1.mp4” -vcodec copy -acodec aac -b:a 192k -f flv “你的rtmp地址/你的直播码”

由于此命令只能运行一次,播放完就停了,所以要实现无限循环播放的话就需要编写一个sh文件,内容如下:

#!/bin/bash while true do ffmpeg -re -i “1.mp4” -vcodec copy -acodec aac -b:a 192k -f flv “你的rtmp地址/你的直播码” done

保存为live.sh,使用下面的命令运行即可(如果没有screen,先使用sudo apt-get install screen安装):

screen nohup sh live.sh &

参考文献:

树莓派安装ffmpeg

使用FFmpeg在B站直播的姿势

出处:https://www.chenxublog.com

树莓派64位系统Debian 9先行测评:性能最高提升30倍!

采用64位处理器的树莓派3B,虽然具有64位硬件,但是系统还没有跟上节奏。官方尚未正式发布64位Raspbian,近期有团队移植了Debian 9 arm64到树莓派3B,将“装死”一年多的树莓派3B的性能完全释放出来,测试跑下来发现CPU性能最高比32位系统高30倍!

本文将介绍如何进行对比跑分测试。

硬件测试环境:

RaspberryPi 3 Model B

16GB Class 10 TF卡

5v2.5A电源

以太网网线及能连外网路由设备

软件测试环境:

GEEEKPI-64bit-beta(内核移植版,操作系统是基于Debian 9的arm64位源码,Debian 9目前还没发布,目前属于beta版,RaspberryPi 官方也没有发布64bit操作系统的计划,但是我们迫切需要64bit的性能)

sysbench 压力测试软件

首先开机后联网,两台设备全部进入字符界面(console)模式,外部不连接任何外设,通过ssh远程登录到两台主机上,然后安装sysbench软件进行压力测试,并通过htop简单的进行观察。

执行命令为:

sudo apt-get update && sudo apt-get –y install sysbench htop iperf3

性能测试命令如下:

#测试CPU性能: sysbench —test=cpu —num-threads=1 —max-requests=10000 run #4线程测试: sysbench —test=cpu —num-threads=4 —max-requests=100000 run #8线程测试: sysbench —test=cpu —num-threads=8 —max-requests=100000 run #测试内存性能 #内存随机测试: sysbench —test=memory –memory-block-size=1K –memory-total-size=1G –memory-access-mode=rnd run #内存连续测试: sysbench —test=memory –memory-block-size=1K –memory-total-size=1G –memory-access-mode=seq run #测试网络性能: iperf3 -c 192.168.1.2 #八线程测试共享线程锁: sysbench –test=threads –num-threads=1000 –thread-yields=1000 –thread-locks=8 run #互斥锁测试 sysbench –test=mutex –mutex-num=4096 –mutex-locks=50000 –mutex-loops=10000 run #连续读写: sysbench –test=fileio –file-num=2 –file-total-size=64M –file-test-mode=seqrewr run #随机文件读写: sysbench –test=fileio –file-num=2 –file-total-size=64M –file-test-mode=rndwr run #进入系统检查系统版本信息及硬件架构平台信息 df -Th

完整测试截图可以在这里下载(感谢yoyojacky提供)。

总结:

GEEEKPI 团队最终对比表格如下:

测试项目 Raspbian2017-03-03 Debian 9 Arm64bit 提升倍数 系统信息 Arm 32bit/ext4文件系统 Aarm64bit/f2fs文件系统 见文件系统测试 CPU单线程 367.2971 25.1195 14.62倍 四线程 1017.6742 62.6079 16.40倍 八线程 1920.0601 62.6711 30.64倍 内存随机 5.7678 2.1925 2.63倍 内存连续 6.3309 2.9392 2.15倍 网络性能 74.6Mbps 94.3Mbps 1.26倍 文件连续读写 5.7655 7.1506 见下文说明 文件随机读写 不支持 21.8336 无 互斥锁性能 0.0231s 0.0186s 1.24倍

Debain 9 文件系统采用了三星与华为合力开发的f2fs,针对mmc和emmc还有tf存储进行了优化,除了大大提升了性能之外,还增加了TF卡的使用寿命,提供了意外断电文件系统的保护,大大避免意外断电导致的文件系统崩溃的情况。

其中由于TF卡的细微差异,导致文件连续读写出现了反转,实际上通过测试文件连续读写的性能方面,f2fs更加优化,超越ext4很多倍。

总体上,64位的系统提供了更好的使用体验,曾经抱怨树莓派跑opencv性能不佳的朋友应该是看到希望了!

以上测试并非使用官方系统,但能够让大家看到软硬件匹配64位之后,树莓派性能上的提升潜力。作为树莓派爱好者,一起期待官方发布64位系统吧!

测试数据摘自:《树莓派64位系统来袭,速度最快提升30倍!》

创客百科启用域名 chuangke.wiki 欢迎入驻~

树莓派实验室“创客百科”用于整理、发布关于创客(Maker)方面的内容和资源,为大家们寻找和梳理知识提供方便。所有词条均开放了编辑权限,欢迎树莓派爱好者加入、共建。

为了方便记忆,创客百科启用了辅助域名 http://chuangke.wiki

欢迎各位树莓派爱好者和创客朋友们收藏。

点这里注册成为百科编辑,登录之后即可开始创作!

如果你已经注册,《编写格式说明》是你生存的基本技能。

想要快速掌握格式语法的使用,建议到沙盒练习场试炼看看。

另外,你还可以选择入驻使用创客笔记服务,将本Wiki用于你个人的共享知识体系。

笔记使用示例:Spoony 的笔记。

创客笔记服务

创客笔记不是像Evernote、有道笔记那种笔记服务,不追求大而全的笔记功能,也不求服务于广泛的用户群体。

创客笔记只为需要以Wiki方式梳理知识,记录知识的你为准备。Wiki是一种很便于归整已有知识和标记未来要去获取知识的系统,它支持的排版十分丰富且易用,详情请看《编写格式说明》,并且能随时查看历史版本方便随心修正完善知识内容。

创客百科免费为需要此服务的用户开放这一工具,你只需要在 note 命名空间下创建一个自己独一无二的节点,比如 note:spoony。并将所有属于自己的内容放在这个命名空间下,比如 note:spoony:myfristnote。有关命名空间的概念请参看《编写格式说明》中相应内容。

为什么要用以上的格式?

便于授权给你只有你才能导出这个命名空间下的内容。

这里接受什么样的内容?

一切合法内容。

这项服务足够可靠值得依赖吗?

尽管没有庞大的用户基数,但是你可以放心使用这项服务,这是同时一对一的服务。任何时候你都可以要求管理人员为你导出备份你命名空间下的数据。同时我们也保证服务的持续可靠运转,承诺即便出现意外情况也会长期通过邮件提供历史数据导出备份服务。你可以拿到备份数据,利用开源的 Dokuwiki 自行搭建一个属于自己的Wiki系统。这样不论何种情况发生你都可以和当前一样持续使用该服务。

一直免费吗?

是的,所有都免费。

我该如何开始?

现在就可以开始。点这里注册成为百科编辑,登录之后输入网址 http://wiki.nxez.com/note:yourid:pagename (其中yourid替换成你的登录名),再点右侧的创建该页面填充页面内容。《编写格式说明》帮助你了解Wiki格式用法,建议一边学习一边到沙盒练习场试炼看看。

Enjoy!

学会阅读Datasheet的基础信息

1、本文适合的读者及申明

首先,本文适合那些菜鸟级的电子爱好者,那些希望自己操起烙铁焊接一些小玩意儿,或者购买一些电子模块来实现自己的互动创意的人们。

本文并不适合专业级别的读者,里面的有些内容的描述为了让爱好者看懂,难免做了一些并不影响原则的曲解。若去强究,则未免贻笑大方。

另外,绝大多数的Datasheet都是英文版的,因此,这也需要读者具备一定的英文阅读水平。

最后,完全读懂一份Datasheet其实是已经可以算是一门相当高超的技能,这不仅需要深厚的电子学知识,IC制造技术,电路设计知识,甚至还会跨越到各种门类的专业学科知识。在这里,作者只能做一个大致的轮廓介绍,至少让读者在未来应用时有一个基本的概念。而完全不敢指望读者读完本文就升仙为Datasheet大神。

申明:本文是一篇实用主义者的自我感悟,并非学术论文,所以,不负文责。

2、 什么是Datasheet?

Datasheet,通常中文翻译为“数据手册”,它是电子零件开发者或者制造者针对其所生产的电子零件而出具的详细描述文件。在Datasheet中,它会描述这个电子零件的各种关键数据。越是复杂的电子零件,其Datasheet就越复杂。而某些简单的电子零件(如普通电阻),则干脆没有(因为它的参数实在是为绝大多数的使用者所了解)。

3、 为什么会有Datasheet?以及学会阅读Datasheet的必要性

电子世界是一个非常复杂的世界,举例来说,哪怕是一块Arduino 主板,上面就有3.3V、 5V和9- 15V三种电压水平。而实际上,我们目前仅从世界上各种电器的工作电压水平而言,就有从最低零点几伏到几万甚至几百万千伏的各种电压水平。不同于一个螺丝螺母,只要外形尺寸对了,拧哪里都是拧(当然,我们不讨论特种环境下的拧螺丝问题)。但是对于电子产品来说,只管电子零件的功能,而不管这个电子零件的适用范围,从而盲目的去使用这些电子零件,这将会无比的荒唐。举个例来说,如果你把一枚LED直接接到220V的电源上,100%,你会听到啪的一声轻响,然后一阵青烟冒起来。而根本就不会看到LED被点亮的效果。

想想,光是一个电压标准就如此地让人无所适从。也正是因为这种复杂性,所以厂商也才会也被迫出具标准的Datasheet来描述它们的电子产品,否则,他们的产品就没人敢用,也没人能用。

4、 为什么要学会阅读Datasheet?

我们学会阅读Datasheet 也是为了解决我们的问题,关联到Arduino,则问题表现为:这个零件能否和Arduino系统直接连接起来,并让它正常工作?如果不能直接连接,那么需要什么样的方法才可以让它和Arduino平台连接?

5、 Datasheet的几个要素

Datasheet 通常包含如下的几个要素:

5.1基本介绍

这个内容一般在首页中会提及,通常含有大量的一句话信息,从这个部分,你可以基本判定这个Datasheet所表述的物料是否符合你的要求。

5.2实现的功能介绍

这个内容会标注零件可以实现的功能,以及正常实现功能的物理环境的要求,或者适用区间。

有些零件还会标注零件在实现功能的时候的先决条件和后续处理,以及零件的最大处理能力。

5.3 引脚配置

这个部分会非常详细的介绍这个零件每一个引脚的定义,你首先往往看到一个图片,上面会标注诸如VCC,VACC,GND,PA等标注。然后紧接着就是一个列表,标明每一个引脚的具体定义,有时候,在这里也会把电气参数标示进去。

5.4零件工作的电气参数:

在这个部分,我们可以了解所描述零件的正常工作电压区间和电流区间,通常情况下,一个电子零件是具有一定范围的“兼容”空间的。而对我们爱好者而言,这个零件的“典型”值,就是我们需要关注的内容。就如LED灯,它通常的典型电流为20mA。

5.5 零件的设置参数和设置说明。

对于某些电子零件来说,它在使用的过程中需要进行各种设置,如三轴加速度传感器,就需要我们事先配置它的内部寄存器,以使得其输出我们需要的数据。在这个部分,我们可以找到一个完整的配置清单及说明。

5.6零件的封装尺寸

同一个功能的零件,即便电器特性完全相同。由于其应用的环境不同,因此厂商也会根据实际的市场需求提供不同的封装产品。就如大家看到Arduino UNO的核心ATMEGA328 一样,它就有三种标准的封装(TQFP,PDIP,MLF)。

5.7 其它

在Datasheet里面还会包含一些其他的信息,如勘误表,版本历史,典型应用电路,零件测试曲线等信息。这些信息也值得大致了解。

6、 对于Arduino 爱好者而言,看Datasheet之前需要明确和在看完之后需要做的。

我们阅读Datasheet的目的不是为了阅读而阅读,与其说Datasheet是一本让人娱乐的小说,倒不如说它是一本无比枯燥的字典。在这个字典中,你可以找到你需要的各种答案。而我们则不仅需要确认它的功能是否解决你的问题,我们还需要确认如何才能让它和Arduino 正确地连接起来。

基于这个原因,我们必须首先对Arduino 主板要有一个基本的了解:

6.1 Arduino的IO口电压是5V,能够支持的最大电流是50MA,通常推荐是20MA。

因此,如果我们看到某个电子零件的Datasheet标注其IO电压是3.3V,那么,最好,我们还是别把它们直接连接在一起,或者我们用电阻分压,或者我们用隔离芯片来进行连接,当然,如何使用这些技巧则是另外一个问题了。

6.2 Arduino UNO的数字端口包含SPI,TWI(兼容于I2C,SCCB等,叫法不同而已),TTL UART,USB SLAVE 四个数据端口。

因此,如果有一个芯片或者零件恰好能够达成你的需要,但是它的接口是SATA。那么,你一样只能干瞪眼。只能想办法转换,而这种转换,同样是另外一个问题。

6.3 Arduino 输出的PWM脉冲是500HZ

如果一个步进电机控制器需要1K的PWM脉冲来进行控制,那么好吧。你用Arduino又搞不定了。又只能间接地采用别的方法来搞定。

就如6.1-6.3所描述的那样,在我们对Arduino有了基本的概念之后,我们才可以开始我们的扩展应用之路。

7 Datasheet在什么时候用?

首先我们大概去找能够达到我们目的电子零件,在购买前,我们先把这个零件的Datasheet拿到手,然后进行分析,充分了解它的各种参数,根据这些参数判断如下问题:

7.1

能否真的达到目的

7.2

能否直接应用或者不能直接应用但可以找到“曲线救国”的方法(如转换电路,适配电路等

当回答完7.1 和7.2两个问题并获得肯定的答案之后,我们后续就只需要买入这个零件,然后按照前面的规划,直接接上Arduino 然后开用就成了。

via 作者 疯叫兽(风的孩子)

树莓派Web物联网遥控灯初试折腾笔记

暑假一段时间也是……闲的蛋疼。就拿出Raspberry准备折腾一番,结果被吐槽“两百多你不如买个二手手机而且性能不会比这个差”“控制灯?你用这个不如用Arduino”

哦,好吧。其实树莓派有GPIO,这个是一个和Arduino类似的东西。但是却有强于Arduino的性能。我们可以研究这个,并且结合起来,凸显它的优势。本文还是主要说明树莓派的web和简单的物联网控制。

于是就动手了。后面发现GPIO用python的socket控制的话,十分麻烦。我不是说写socket麻烦,而是不容易跨平台控制,于是便有了用web的想法。可惜我web只是入门,python写不出,所以就用了稍稍会那么一点的php。因为关于GPIO的介绍这里和百度很全了,所以我也就不再说哪个针脚是哪个。为了方便和安全,我这里没用继电器控制电灯。使用了LED灯组。同时我也不推荐像使用强电。实验准则人身安全是第一位的。特别是还在调试阶段就更不应该使用强电。你需要:

树莓派B or B+ or 3 一个,并有套件且装好系统(A的话可能针脚有所不同不过没关系,源别瞎改)

杜邦线若干(母对母)

电脑一台,有良好的开发环境和putty之类的管理程序

网络

LED灯组(单个也没问题)

因为本人新手又是不太熟悉linux和GPIO的人,所以不免绕了许多路。所以你可能还需要一些linux操作基础。

先连接硬件。LED灯组如果不喜欢就用单个LED,为了防止烧坏建议串联100欧姆的电阻,因为工作电流可能会很大(相对于LED额定电流)。因为二极管有单向导电性所以LED长腿是正极断腿负极。不要接错,接错没关系,检查以后接回来即可。Tips:给那些没玩过太多电子电路无线电的朋p友y说粗略明下串联电阻是有必要的,如果没电阻也可以拆拆废电器,没有电烙铁可以用打火机加热的粗铜丝一头裹东西拿着去触碰焊点,可以有电烙铁一般的效果,轻松拆下元器件。电阻会有四个色环,按着金色或者银色是最后一个的顺序第一个是第一个数字第二个是第二个数字第三个环是倍数,十的幂次。金色和银色代表误差。按着棕红橙黄绿蓝紫灰白黑表示1234567890。比如[棕黑棕(金或银)]是100欧姆(棕1黑0棕x10^1),[棕黑红(金或银)]是1KΩ(1 0 x10^2)。这里100欧姆即可。太大电阻影响亮度。如果电阻腿够长,你可以尝试铰接。拧一块就行。

好的,一切都准备好,连接上pi然后先解决py问题

pip install rpi.gpio

这个在新版的系统里默认安装好。

在电脑上写py

#!/usr/bin/python import sys import RPi.GPIO as GPIO GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) args = sys.argv Act = args[1] pin = 17 GPIO.setup(pin,GPIO.OUT) if(int(Act)==1): GPIO.output(pin,GPIO.HIGH) print “HIGH” if(int(Act)==0): GPIO.output(pin,GPIO.LOW) print”LOW”

注意这里RPi.GPIO,是RPi!i是小写,当时我按了大写,怎么也不能引用……

setwarning(False) 屏蔽一些错误和提示信息并强制执行

setmode是选择一种针脚编码方式,有BOARD和BCM两种,有兴趣可以看看。在上面链接里第二个有详细的介绍。我们这里就用BCM了

到了这个时候就可以保存你的py并且上传到你的pi上

python gpio.py 1 #输出高电平 python gpio.py 0 #输出低电平

这个时候你会发现你已经可以控制一个灯的开关。如果真的这样那么恭喜您。你可以考虑用web控制了。

我在这里也用的是lamp(m划掉,实际上这里没用到,后面也不提了)

提醒一下大家树莓派的源真心别瞎改,我当时改的,然后先是各种依赖不行,然后更恶心的是解决了依赖然后搞了个Debian的Apache2,连httpd.conf都没有,然后去mod里面软连。php又是各种问题,后面尝试nginx时cgi又有问题……最后改回来又花了很大劲……

原生源安装特别方便:

sudo apt-get install apache2 php5

然后电脑浏览器打开即可。你会发现默认页面里还有个树莓LOGO。

/var/www/html里添加一个php测试一下

成功往下看:

好了,这就行了。十分方便。我为此写了一个php+html(在下不是phper也不会前端所以要求不高,界面不美观。只是觉得那个FB的PHP有可以改进之处,水平问题,我只能尽量安全可靠,方便调试)

The show start when the lights on 

<style>” title=”</p>
<style> Light Controller >

".file_get_contents("/var/www/html/l.txt").""; //错误在/var/www/html/l.txt可以自己定,这里显示错误方便调试 } } $p='wtf'; //令牌,自己改 $bool=false; //$bool控制Permission Denied显示 @$act=$_POST['act']; //获取post得到令牌和动作,@屏蔽刚刚打开时的提醒 @$pwd=$_POST['pwd']; // $bool=isset($pwd)?true:false; //判断如果有pwd传入,赋值true显示permission Denied,这里为了防止一打开就看到 if ($p===$pwd) { //传入密码和定义的一样的话 if($act==='ON'){ //###开灯动作,把www-data加入soduer然后sudo,用visudo,具体网上有说的 $return=shell_exec("sudo python /var/www/gpio.py 1 2>/var/www/html/l.txt"); //运行shell,如果出错,错误信息重定向至显错文件/var/www/html/l.txt echo 'Light ON!--->'; //输出开灯和箭头 echo "$return "; //输出py运行结果 debug((string)$return); //执行调试函数 } // elseif ($act==='OFF') { //判断关灯动作 $return=shell_exec("sudo python /var/www/gpio.py 0 2>/var/www/html/l.txt"); //###(接上shell_exec)因为会调用/dev/mem和/dev/gpiomem,需要root.关灯动作执行 echo 'Light OFF!--->'; //输出关灯和箭头 echo "$return "; // debug((string)$return); // } // else{ // echo 'Error!'; //如果post的数据不是ON,不是OFF,那就丢出ERROR } // } // else // { // if($bool){echo "Permission Denied!";} //密码不对,或者只传入动作,输出这句 } // ?>

这里我已经把我的php注释的十分详细了吧=_=debug函数为了调试shell_exec()方便

“The show start when the lights ON——rustylake”

注意:www-data要sudo这个注释里面说了,重定向输出可以方便的检查出错,因为出错时输出不是标准输出所以返回为空。我为了方便检查,所以重定向错误到文件并输出。方便了很多。权限问题很重要,当时基本出错都是这个。比如文件无法访问问题,命令执行时可能还有问题。。还有/dev/mem的问题,这玩意错了还不回显所以只能自己附带函数调试。本代码移植性不一定好。所以可能自己需要改改。我已经做的尽量安全,美观了。并且附带调试函数。可以显示错误信息方便调试,避免走弯路。(当时被坑惨了)

虽然这里已经不直接调用post来进行shell_exec(),并且带上一个密码验证。安全性较FB文有所提升,但依然是实验而且本人php仅仅入门。所以能不能对外网开放请再三考量。

转自 http://www.restkhz.com/2016/07/raspberry-pi-b-web/

3D打印机加个树莓派实现3D打印“云”

前一段蹭小伙伴的3D打印机,打印前每次都要把内存卡插电脑上复制Gcode,好累的说,于是有了下文。题主正好有块闲置树莓派于是就派上用场了。

简单介绍下 Octoprint

官网:octoprint.org

wiki:https://github.com/foosel/OctoPrint/wiki

通过Python脚本登录SSH给树莓派发送控制指令

来自树莓派实验室群果果投稿,文末有演示视频。

最近这几天作为小学生的我有些无聊,毕竟学校的任务还是很简单的,对我一点没有难度。所以我就想起了半年之前买的树莓派,当时好一个折腾,还入手了一个扩展板,就是为了学习关于GPIO的知识,但是最后因为事情太多而放下了。重新捡起树莓派的我开始考虑要写什么程序:“最近智能家居这个词经常在广告上出现,反正我也闲的没事情干,编个程通过Windows来控制Pi的扩展板吧,估计效果能挺不错的。最近看实验室也有个类似的项目,我也来尝试一下。”

制作这个小程序需要树莓派一个(需要可以支持扩展板的),装好Raspbian系统。然后需要一个瑞士军刀扩展板(在实验室里有卖的,反正功能特全),再就是要在计算机上安装PuTTY了。就这三样。做起来也不难。(我相信正在阅读本文的你一定是有网络的吧……)

因为在这个过程中涉及了PuTTY也就是命令行工具,所以大家还需要掌握一些Linux Shell的知识。关于扩展板……你肯定是能装上的,然后把扩展板压紧防止出现短路问题。

安装完成后,先在Raspbian里面安装Python和Git,因为不管是裸操控GPIO,还是使用扩展板已经开发好的SDK,都是要以Python作为支持的。而我这里用的是SDK,这个SDK是托管到GitHub上的。安装完以后,新建一个目录,我这里新建的是~/Raspberry_pi_study/SAKS/RemoteControl文件夹,大家可以用mkdir来创建。进入以后,我们先git clone 一下。

sudo git clone https://github.com/spoonysonny/SAKS-SDK.git

然后将SDK直接复制到文件夹下(注:clone命令会自动生成SAKS-SDK这个文件夹,而我们并不需要,可以用cp命令将它拷贝过来然后用rm -rf删除掉多余的文件夹。)克隆完毕以后,删除main.py,重新建立一个。在里面输入以下代码:

#!/usr/bin/env python # -*- coding: utf-8 -*- from sakshat import SAKSHAT import time import commands import sys #Declare the SAKS Board SAKS = SAKSHAT() args = sys.argv action=args[1] if __name__ == “__main__”: if action==”beep”: SAKS.buzzer.beep(int(args[2])) if action==”ledon”: if args[2]==”all”: SAKS.ledrow.on() else: SAKS.ledrow.on_for_index(int(args[2])) if action==”ledoff”: SAKS.ledrow.off() if action==”getledstatus”: print(SAKS.ledrow.is_on(int(args[2]))) if action==”displaynum”: SAKS.digital_display.show(args[2]) if action==”displayoff”: SAKS.digital_display.off()

写完代码以后保存,然后退出PuTTY,至此,Pi端的准备工作已经完成,下面进入Windows远程控制端的操作。

我在树莓派实验室看到的另一篇文章是用PHP进行了操作,可是不知道为何我的PHP就是搭建不起来。所以只好使用另一种方案——paramiko。

paramiko是一个Python ssh的一个工具,他可以用Python远程连接并且远程执行命令。我认为他就是是Python中的PuTTY。在这里,我用的是pip安装。

sudo pip install paramiko

安装完成以后新建一个py文件,然后输入以下代码:

import paramiko import sys def ssh_connect( _host, _username, _password ): try: _ssh_fd = paramiko.SSHClient() _ssh_fd.set_missing_host_key_policy( paramiko.AutoAddPolicy() ) _ssh_fd.connect( _host, username = _username, password = _password ) except Exception, e: print(‘Authorization Failed!Please check the username,password or your device is connected to the Internet.’) exit() return _ssh_fd def ssh_exec_cmd( _ssh_fd, _cmd ): return _ssh_fd.exec_command( _cmd ) def ssh_close( _ssh_fd ): _ssh_fd.close() def print_ssh_exec_cmd_return(_ssh_fd,_cmd): stdin,stdout,stderr=ssh_exec_cmd(_ssh_fd,_cmd) err_list = stderr.readlines() if len( err_list ) > 0: for err_content in err_list: print ‘ERROR:’ + err_content exit() for item in stdout: print item if __name__ == ‘__main__’: sshd = ssh_connect( ‘192.168.1.121’, sys.argv[1], sys.argv[2]) print ‘Executing \”+sys.argv[3]+’\’ command,remote controlling raspberrypi.’ if len(sys.argv)==4: print_ssh_exec_cmd_return(sshd,’cd Raspberry_pi_study;cd SAKS;cd RemoteControl;python main.py ‘+sys.argv[3]) else: print_ssh_exec_cmd_return(sshd,’cd Raspberry_pi_study;cd SAKS;cd RemoteControl;python main.py ‘+sys.argv[3]+’ ‘+sys.argv[4]) ssh_close( sshd )

其中,sys.argv[1]是用户名,sys.argv[2]是密码,sys.argv[3]是基础命令 sys.argv[4]是高级命令(基础命令就是对应Pi端中的 ledoff displayoff之类的只需要一个参数即可完成的命令,高级命令比如ledon后面还要跟着一个all 或者一个数字,分别代表了全部开灯和只开一个灯,这里空格就是两个完全不同的命令行参数,所以必须有argv[4])

写完代码以后,大家可以保存运行一下:remotecontrol.py ledon all。remotecontrol.py ledoff。remotecontrol.py displaynum 1.2.6.8(哦对了,这里千万不能出现#后面跟着数字,虽然在SDK中#代表没有这个数字,但是Python会认为它是注释,所以会把后面的数字全都注释掉,也就是什么数字都没有,所以会出现index out of bounds的问题。这个问题有点像SQL注入,我也不深入讲了……)这时可以发现,在Windows端也可以轻松控制Pi了!我们也就成功达到了远程控制的目的了!

视频演示:

(我的树莓派网络IP是固定的,是192.168.1.121,如果你的IP是DHCP自动分配的,建议你将DHCP改为static或者添加一个args让他可以动态访问IP)

来自树莓派实验室群果果投稿,转载请注明出处。

厨房又添一宝:用树莓派做个自动调酒机

来点喝的吧

有没有到过低劣酒保驻场的派对?还是连酒保都没有的?谁也不想碰到宁可把喝的用来祭奠先人的地步。BarBot(酒吧机器人)能改变这一现状!BarBot是个简单有有效率娱乐大众,把来客们灌醉的机器人。安装在机器上的四种液体罐能以各种方式混合调配。我设计了BarBot,派对来宾们可以大喇喇走上去,把杯子放在平台上,在简单界面上(可通过智能手机或平板电脑操作)选择饮料。它同时配有有趣的载入画面,让你知道你的饮料正在调配中,完成之后就可以选择另一个选项。来,干了!

如何工作的呢?

树莓派监听两个端口,一个是apache2网络伺服器,在80端口上,另一个是Golang,在8080端口上。菜单页面被平板电脑或智能手机载入后,当在网页界面选择一个按钮时,其他选项就被隐藏起来,所以是无法进行多选的。接着生成发往BarBot程序的AJAX请求,BarBot收到请求,然后通过触发相关液体泵的继电器来调配选择的饮料(通常一个泵能每秒倒出1毫升液体)。在饮料倒完之后,BarBot程序对AJAX请求通过载入页面进行回应。菜单按钮就返回信息“完成调配饮料”给用户。

BarBot零件清单:

树莓派A型、SainSmart 8通道继电器模组、Adafruit液体蠕动泵、USB WiFi网卡、给树莓派用的2安USB充电器、液体泵用12伏电源适配器、12伏绿色LED灯带、散热管、地漏、桶、黑色开发板。

为何选择这样的配置?

既简单,大部分零件廉——价!

选择树莓派A型是因为它能准确驱动8通道继电器模组。如果你用树莓派B型,那控制这个模组就有点困难。选择Adafruit液体蠕动泵是因为蠕动泵本身从不接触液体,只是它通过“按摩”管道的方式将液体抽取上来。(也就是挤压滴管的原理。)

包装

当我用123D Design软件完成建模设计后,我跑到本地五金店里采购所需材料。首先我在黑板上开始安装,它既轻便又外形好看,但最主要原因是我喜欢在它身上写菜单或BevOps的数学算式这种创意。前面板用透明亚克力板打造,每个人都能观赏这手工制品。另外,绿油油的灯光更是让它看起来充满未来感!

代码

我对BarBot编程,使它能处理四种液体。后来我加上了它能离线处理调配文件的功能,但现在它还只能调配威士忌、伏特加、橙汁和红莓汁这四种。在这里能下载程序代码。将代码编译为嵌入式系统运行的,然后将index.html放到在树莓派上的Apache服务器里。

延伸功能

我增加了BarBot接收语音命令的功能,通过Tasker和AutoVoice来完成简单的GET请求,得到特定的饮料。

最终展望

BarBot在我带去的每场派对中已形成巨大人气,同样办公室白领也对它青睐有加(当然,我们上班时都会喝东西)。当机器人能为你倒饮料时,我们为何还要自己动手呢?我,其中一个欢迎机器人君临人类世界的人,只要它们能一直用喝的把我供着就成。

via 原作:Shazbot

厨房又添一宝:用树莓派做个自动调酒机

Facebook开源Caffe2:可在树莓派上训练和部署模型

机器之心编译

在今年的 F8 开发者大会上,Facebook 正式宣布开源其全新深度学习框架 Caffe2。据 Caffe2 官方博客介绍,该框架可以用在 iOS、Android 和树莓派上训练和部署模型;而且 Facebook 已经与英伟达、高通、英特尔、亚马逊和微软等公司展开了合作来实现对移动端的优化。机器之心在此对这一开源项目进行了介绍。

为了有效地训练和部署人工智能模型,我们往往会用到大型数据中心或超级计算机。为了能够大规模地连续处理、创建和提升各种各样的信息(图像、视频、文本和音频)之上的模型,我们需要的计算能力不可小觑。如果我们要在移动设备上部署这些模型,那么它们就必须要非常快而且轻量,但这也同样十分困难。要克服这些难题,我们需要一种稳健的、灵活的和便携式的深度学习框架。

Facebook 一直以来都在和开源社区的其他开发者合作一起打造这样一款框架。今天,Facebook 宣布开源了第一版生产可用的 Caffe2 版本,这是一个轻量级的、模块化的深度学习框架,并且在强调了便携性的同时保持了可扩展性和性能。

我们致力于为社区提供高性能的机器学习工具,以便人人都能创造智能的应用和服务。与 Caffe2 一同发布的还有相关的一些教程和案例,其中包括在一台机器上使用多个 GPU 的大规模学习和使用一个或多个 GPU 的在多台机器上的大规模学习、学习在 iOS、Android 和树莓派上训练和部署模型。另外,你只需要编写几行代码就能调用来自 Caffe2 Model Zoo 的预训练模型。

Caffe2 部署在 Facebook 之中以帮助研发人员训练大型机器学习模型,并为手机用户提供人工智能驱动的良好体验。现在,开发者可以访问很多相同的工具,允许他们运行大规模分布式训练方案,并创建手机端的机器学习应用。我们已与英伟达、 高通、英特尔、亚马逊和微软展开密切合作,从而在云端和手机端优化 Caffe2。这些合作将允许机器学习社区快速完成使用更复杂模型的实验过程,并部署下一代人工智能增强型应用和服务。

你可以在 caffe2.ai 上查看 Caffe2 文档和教程,并在 GitHub 查看源代码。如果你考虑使用 Caffe2,我们很乐意了解你的具体需求。请参与我们的调查。我们将向你发送有关新版本和特殊的开发者活动/网络研讨会的信息。

以下是 Caffe2 在 GitHub 上开源项目的介绍:

Caffe2 是一个兼具表现力、速度和模块性的深度学习框架,是 Caffe 的实验性重构,能以更灵活的方式组织计算。

许可

Caffe2 的发布许可许可 :https://github.com/Yangqing/caffe2/blob/master/LICENSE

建立 Caffe2

详细的构建矩阵:

sudo git clone –recursive https://github.com/caffe2/caffe2.git cd caffe2

OS X

brew install automake protobuf mkdir build && cd build cmake .. make

Ubuntu

可运行版本:

Ubuntu 14.04

Ubuntu 16.06

需要的依赖包

sudo apt-get update sudo apt-get install -y –no-install-recommends build-essential cmake git libgoogle-glog-dev libprotobuf-dev protobuf-compiler python-dev python-pip sudo pip install numpy protobuf

可选择 GPU 支持

如果你计划使用 GPU,而不只是使用 CPU,那你应该安装 NVIDIA CUDA 和 cuDNN,这是一个面向深度神经网络的 GPU 加速库。英伟达在官方博客中详细介绍了安装指南,或者可以尝试下面的快速安装指令。首先,一定要升级你的图显驱动!否则你可能遭受错误诊断的极大困难。

安装 Ubuntu 14.04

sudo apt-get update && sudo apt-get install wget -y –no-install-recommends wget “http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1404/x86_64/cuda-repo-ubuntu1404_8.0.61-1_amd64.deb” sudo dpkg -i cuda-repo-ubuntu1404_8.0.61-1_amd64.deb sudo apt-get update sudo apt-get install cuda

安装 Ubuntu 16.04

sudo apt-get update && sudo apt-get install wget -y –no-install-recommends wget “http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_8.0.61-1_amd64.deb” sudo dpkg -i cuda-repo-ubuntu1604_8.0.61-1_amd64.deb sudo apt-get update sudo apt-get install cuda

安装 cuDNN(所有都是 Ubuntu 版本)

CUDNN_URL=”http://developer.download.nvidia.com/compute/redist/cudnn/v5.1/cudnn-8.0-linux-x64-v5.1.tgz” wget ${CUDNN_URL} sudo tar -xzf cudnn-8.0-linux-x64-v5.1.tgz -C /usr/local rm cudnn-8.0-linux-x64-v5.1.tgz && sudo ldconfig

可选择的依赖项

注意,Ubuntu 14.04 使用 libgflags2。Ubuntu 16.04 使用 libgflags-dev。

# for Ubuntu 14.04 sudo apt-get install -y –no-install-recommends libgflags2 # for Ubuntu 16.04 sudo apt-get install -y –no-install-recommends libgflags-dev # for both Ubuntu 14.04 and 16.04 sudo apt-get install -y –no-install-recommends libgtest-dev libiomp-dev libleveldb-dev liblmdb-dev libopencv-dev libopenmpi-dev libsnappy-dev openmpi-bin openmpi-doc python-pydot

检查下面的 Python 部分,并在建立 Caffe2 之前安装可选择的程序包。

mkdir build && cd build cmake .. make

安卓和 iOS

我们使用 CMake 的安卓和 iOS 端口构建原始二进制文件,然后就能将其集成到安卓或 XCode 项目中。查看脚本/build_android.sh 和/build_ios.sh 获得具体信息。

对于安卓系统,我们可以使用 gradle 通过 Android Studio 直接构建 Caffe2。这里是一个示例项目:https://github.com/bwasti/AICamera。注意,你可能需要配置 Android Studio,这样你编写代码的 SDK 和 NDK 版本才会正确。

树莓派

对于 Raspbian 系统,只需要在树莓派上运行脚本/build_raspbian.sh 就行了。

Tegra X1

为了在英伟达的 Tegra X1 平台上安装 Caffe2,需要使用 NVidia JetPack 安装器简单地安装最新版本的系统,然后再在 Tegra 设备上运行脚本/build_tegra_x1.sh。

Python 支持

为了进行下面的教程,Python 环境需要安装 ipython-notebooks 和 matplotlib,在 OS X 系统中可以通过以下方法安装:

brew install matplotlib –with-python3 pip install ipython notebook

你会发现下面的 Python 库同样在具体的教程和案例中是必需的,所以你可以运行下面的命令行一次性安装所有的要求库:

sudo pip install flask graphviz hypothesis jupyter matplotlib pydot python-nvd3 pyyaml requests scikit-image scipy setuptools tornado

构建环境(已知能运行)

原文链接:http://caffe2.ai/blog/2017/04/18/caffe2-open-source-announcement.html

树莓派DIY自带特效的智能安全门

来自树莓派实验室老司机群 Pokebox 的投稿~,文末有 Pokebox 同学录制的炫酷视频不要错过!

自从上次在树莓派实验室发了那个《用树莓派DIY一个智能家居服务器》后,反响比较强烈~~

直到最近都还有朋友给我发邮件说想学习交流~嗯,那时是刚高考完,现在也上大学了,在学校也有了自己的工作室,于是就在工作室里把家里那套系统搬了过来弄了一下~把工作室小改造了一番。

当然,改造的最多的还是工作室的这扇门~所以这次着重讲的也是这扇门~

之前是这个样子的,普通的机械锁,有个把手,开门全靠钥匙。虽然学校装了电磁门禁,门口旁边也有个刷卡器,但是并没有使用。

现在还是只是用钥匙开门。在得到老师的同意和指示后,召集小伙伴七手八脚的就把门锁先给卸了~

当然,可能到这大家有点看不明白我们打算要干嘛~

先说明一下目的,嗯,由于普通的门锁想要用电子控制,要么得在锁上装舵机,通过机械的方式拉开锁舌开门,要么完全用电磁之类的吸合。之前是打算把这个把手直接拆掉只用上面的电磁门禁,但是这会出现一个问题,万一停电了,门没办法锁;或者出了故障,又没钥匙开门。所以折中方案就是选择这种电机控制的门锁。这种门锁在楼宇门禁还是经常见的,相信大家并不陌生。

在换好锁后,因为锁本身就支持钥匙开门或者按开关开门,所以我就直接弄了根网线,把电源线开关线接出来

然后,把这根网线弄到原来的开门开关上,当然,先把原来的刷卡面板卸了~

这是原来接在外面的刷卡面板的线,埋在出门开关的盒子里……全剪掉,然后拆了刷卡面板,把开关和现在接的网线连接起来,然后调试锁

(做的时候其实是先调试好了锁才考虑用什么方式走线的……一开始打算在门上钻孔走内部,但是不好弄,就直接拉网线走门边控制)

一切调试好后,就把树莓派放上,加上树莓派远控(毕竟结合原来的那套系统嘛,继续考虑手机控制)

树莓派也放上去后,因为把刷卡器拆了,外面的墙上有个洞不好看,先用3D打印机打了块板子临时盖着遮一下……

之后打算在这个位置弄密码键盘,按密码开门。

说干就干,抄起单片机,买几片薄膜键盘,设计好外壳,走起~

先用单片机+薄膜键盘做密码键盘的输入,通过串口把获取到的按键值发给树莓派去识别和操作。这里我用了#号键作为密码输入结束的确定键。

单片机程序和树莓派程序调通后,打印外壳,焊板子(因为体积关系不可能直接塞个直插封装的单片机下去,所以就买了比较方便焊接体积又相对小的DIP封装的单片机,这里用了STC15系列的单片机,可以省掉晶振的焊接)

因为之前还打算设计语音开门,所以留了个麦克风的孔……

单片机读键盘数据的代码如下(单片机使用的是STC15W404AS型号)

#include “STC15W404AS.h” #include #define key_port P1 //键盘接口定义 sbit key_port_0=key_port^0; sbit key_port_1=key_port^1; sbit key_port_2=key_port^2; sbit key_port_3=key_port^3; sbit BEEP=P5^5; //蜂鸣器 sbit OPEN=P5^4; //开门按键 /******************************* STC15W404单片机一毫秒延时函数 *******************************/ void delay_ms(unsigned int ms) { unsigned char i, j; while(–ms){ _nop_(); _nop_(); _nop_(); i = 11; j = 190; do { while (–j); } while (–i); } } /************************** 串口发送一个字符 **************************/ void com_send_dat( unsigned char dat) { SBUF=dat; while (TI== 0); TI= 0 ; } void init_com(void) //T2_9600bps@11.0592MHz { SCON = 0x50; AUXR |= 0x01; AUXR |= 0x04; T2L = 0xE0; T2H = 0xFE; AUXR |= 0x10; } /************************** 键盘扫描函数 **************************/ unsigned char keyscan(void) { unsigned char key,i; unsigned char code key_table[16]={0xeb,0x77,0x7b,0x7d,0xb7,0xbb,0xbd,0xd7,0xdb,0xdd,0x7e,0xbe,0xde,0xee,0xe7,0xed}; key=0xFF; //输出初始化值 key_port=0x0f; //确定行列位置 if(key_port==0x0f) return(255); //无键按下返回0 delay_ms(5); //调用延时函数 ,目的是去前沿键抖。 if(key_port==0x0f) return(255); //再次判断。目的是确保检测正确 else { for(i=0;i<4;i++) //以下为经典的计算键值(判断闭合键所在的位置) { key_port=_cror_(0x7f,i); if(key_port_0==0) break; if(key_port_1==0) break; if(key_port_2==0) break; if(key_port_3==0) break; } key=key_port; //取得键值 for(;key_port!=0x0f;key_port=0x0f); //等待键松开,目的是去后沿键抖 for(i=0;key_table[i]!=key && i<16;i++); //查表取key的值0-F key=i; return(key); //带键值返回主调函数 } } /************************** 键盘扫描测试主函数 **************************/ void main(void) { unsigned char key,nok; init_com(); //串口初始化 nok=0; while(1) { key=keyscan(); if(key!=0xff) { BEEP=0; com_send_dat(key+0x30); delay_ms(20); BEEP=1; } if(OPEN==0) //如果从里面按下了开关则发送一个字符串 { com_send_dat('Y'); com_send_dat('E'); com_send_dat('S'); com_send_dat('O'); com_send_dat('P'); com_send_dat('E'); com_send_dat('N'); while(!OPEN); delay_ms(10); } } } 单片机控制开门的代码 #include #include sbit IN1=P1^0; //霍尔传感器1 sbit IN2=P1^1; //霍尔传感器2 sbit OUT=P2^0; //门控制 sbit RELAY=P2^1; //继电器 bit OFLAG = 0; //状态标记 void Delay100ms(unsigned int t) //@11.0592MHz { unsigned char i, j, k; while(–t) { //_nop_(); //_nop_(); i = 5; j = 52; k = 195; do { do { while (–k); } while (–j); } while (–i); } } void main(void){ unsigned char i; P1M0=0xff; //高阻输入 P1M1=0xff; //P2M0=0x00; //推挽输出 //P2M1=0xff; IN1=1; IN2=1; OUT=1; RELAY=1; while(1){ if(IN1==0 && OFLAG==0) { OUT=0; //开门 OFLAG=1; //标志一下现在状态是开门 for(i=0;i<9;i++) { RELAY=0; Delay100ms(3); RELAY=1; Delay100ms(3); } RELAY=1; OUT=1; } else if(IN2==0) { OFLAG=0; } } } 把薄膜键盘贴上去,板子直接上热熔胶固定。蜂鸣器作为按下按钮时发出滴滴的提示音用~ 一切搞定后装壳上墙~ 效果其实还是很不错的。 这一切弄完了,试了一两天发现还是有点不够完美,上面的电磁锁我们也打算利用起来。 由于这个门锁是电磁感应式锁门的,不是碰撞式锁门,所以在关门时锁上的传感器感应到锁口的磁铁时才视为当前是关门状态,然后才伸出锁舌锁门。如果我们用常规的关门方式带门就走,门在关上瞬间由于惯性会反弹一下,所以在关门的时候不得不温柔的拉上门,等锁舌伸出后才能走。但是由于装了这个锁没把手,关门就成了比较蛋疼的事情。 刚好,如果加上上面的电磁锁,在关门的时候吸住门,这样门就不会弹开了。但是,还有个问题……如果让电磁锁一直通电的话,下面的锁开了,上面还吸着门,门还是打不开。如果不吸,又会出现关门比较麻烦的事情。就算用树莓派来控制,在输入密码的时候开门自动断开它的电源同时开锁,但是如果是用钥匙开的话,就没办法打开它了。怎么办?如何才能做到开锁后门磁断开,能顺利开门,关门的时候又可以加磁吸住门同时无论用密码还是远程或是直接用钥匙开门都能打开电磁锁呢? 我反复研究了一下这个锁,发现里面有3个霍尔传感器,一个是之前说的用来判断锁是否处于关门状态自动锁上的,另外两个传感器位于锁舌附近,是拿来判断锁舌位置的。因为发现这个锁在开着门的状态如果强行拉出锁舌,会报警,几秒后自动收回锁舌。在处于关门状态时,如果长期没动,锁舌也会自动伸出锁门。 正好,利用这两个判断锁舌位置的传感器就可以完成在锁舌收回的时候断开电磁锁开门。 这里我又单独用了一块单片机来判断这些传感器的位置并控制门磁,不使用树莓派一起控制的目的是防止万一树莓派死掉了,这部分独立的电路还能保证门锁可以正常打开。 这样一番改造后,工作室的门就可以通过多种方式开门,既可以使用密码盘输入密码进入,也可以远程通过手机或者电脑开门,在停电或者故障的时候,还可以使用备用的钥匙开门。这样做就可以很好的分配用户权限,因为可以设置每个人的密码都不一样,这样就可以通过识别不同人的密码判断谁在什么时间进入了工作室,连考勤都可以省了~管理员还可以通过远程查看登录记录知道今天谁来了谁没来;或是管理员出门在外有外来人员想参观工作室的时候,就可以远程开门给领导老师进去检查参观,就不会造成因为人不在而进不了门的尴尬~ 以及在有人来访的时候,还可以设置访客密码,演示的时候使用这个访客密码进入树莓派会播放欢迎的语音,并向墙壁投影一个虚拟人物欢迎~提升工作室的科技感~ 嗯,之后还打算继续完善这个工作室,把空调,电灯之类的控制完善起来,变成一个全智能的工作室~ 最后让我们视频预览一下这个智能门有什么炫酷特效,欢迎弹幕吐槽! (bilibili 吐槽请移步 http://www.bilibili.com/video/av9021381/) 编者提示:本文中有关树莓派作为上位机如何通过串口与单片机进行通信,树莓派实验室之前的文章有介绍相应的方法,可以参考: https://shumeipai.nxez.com/2017/01/31/raspberry-serial-programming-python-example.html https://shumeipai.nxez.com/2015/03/26/raspberry-pi-serial-programming-sending-and-receiving.html

基于PHP探针和Python爬虫的服务器监控

来自 SPtuan 的投稿~

服务器监控助手,基于PHP探针和Python爬虫。用爬虫抓取PHP探针反馈的实时信息,比如网速、负载、内存等等,然后显示在1602显示屏上。让你随时监控服务器状态。

关键词:PHP探针、服务器监控、VPS监控、Python、树莓派、Raspberry Pi、1602。

0.序言

本实验在我的RaspberryPi 3b 上完成, Python3 。

我这个思路也算是骨骼清奇了,套了一圈用探针抓服务器信息。

不过对于一个本身运行着PHP的建站服务器,多挂一个探针并没有什么损耗。

我的ipv6代理服务器很受欢迎,因此按需求来讲,我需要一个能实时监控流量的工具。PHP探针作为一个很方便的工具,成为了我的选择。但是自带的web界面对我来说不是很方便。

某天我在床上躺尸的时候突然想到,大家天天剁手买VPS以针会友。如果我直接用树莓派抓取探针返回的服务器状态,显示在1602上,从此开始日日夜夜躺在沙发上看着数据跳动,岂不美哉?本

玩了一假期的树莓派,之前做项目剩了很多1602屏幕。它们之间的组合,就有了今天的作品。

1.雅黑PHP探针

1.1 关于PHP探针

关于PHP探针,给不知道的读者说道说道。

雅黑实验室

【雅黑PHP探针】

雅黑PHP探针最大的优点:每秒更新,不用刷网页。有一个负责的站长,会对探针进行长期支持和更新。

用于Linux系统(不推荐使用于Windows系统)。

可以实时查看服务器硬盘资源、内存占用、网卡流量、系统负载、服务器时间等信息,1秒钟刷新一次。

以及包括服务器IP地址,Web服务器环境监测,php等信息。

php探针对于经常购买VPS折腾的人肯定不陌生,简单地老说就是一个可以获取系统信息并在网页上显示的php程序。雅黑PHP探针的界面如下:

我一个Digitalocean服务器上挂的演示探针:http://tyo01.misaka.cc:10086/tz.php

因此,经常有人买各种廉价小内存的VPS,只能挂个探针,却因此获得巨大快感,并从bbs上交流。叫做以针会友。

1.2 分析

打开探针网页可以看到循环刷新的服务器信息。思路很简单,用简单的Python爬虫去爬这个网页。

首先打开探针网页分析一下。

演示:

http://tyo01.misaka.cc:10086/tz.php

可以看到服务器实时数据表格,是动态刷新的。因此,直接爬取该网页的html并不能持续获取服务器信息。既然有动态刷新,想必服务器和客户端之间必有数据包传输。在Chrome中,按F12开始审查网页,进入Networking标签栏。

可以立刻找到动态刷新请求的url。该url是

http://tyo01.misaka.cc:10086/tz.php?act=rt&callback=jQuery1705809678890101435_1487402170358&_=1487402269387

直接访问该url,返回的是以下数据。

jQuery1705809678890101435_1487402170358({“useSpace”:”3.985″,”freeSpace”:”15.577″,”hdPercent”:”20.37″,”barhdPercent”:”20.37%”,”TotalMemory”:”490.23 M”,”UsedMemory”:”414.12 M”,”FreeMemory”:”76.11 M”,”CachedMemory”:”84.05 M”,”Buffers”:”104.9 M”,”TotalSwap”:”0 M”,”swapUsed”:”0 M”,”swapFree”:”0 M”,”loadAvg”:”0.00 0.00 0.00 1\/117″,”uptime”:”3\u59293\u5c0f\u65f626\u5206\u949f”,”freetime”:””,”bjtime”:””,”stime”:”2017-02-18 15:17:56″,”memRealPercent”:”45.93″,”memRealUsed”:”225.17 M”,”memRealFree”:”265.06 M”,”memPercent”:”84.47%”,”memCachedPercent”:”17.15″,”barmemCachedPercent”:”17.15%”,”swapPercent”:”0″,”barmemRealPercent”:”45.93%”,”barswapPercent”:”0%”,”NetOut2″:”44 K 505 B “,”NetOut3”:”2 G 825 M 602 K 970 B “,”NetOut4″:””,”NetOut5″:””,”NetOut6″:””,”NetOut7″:””,”NetOut8″:””,”NetOut9″:””,”NetOut10″:””,”NetInput2″:”44 K 505 B “,”NetInput3”:”3 G 145 M 314 K 713 B “,”NetInput4″:””,”NetInput5″:””,”NetInput6″:””,”NetInput7″:””,”NetInput8″:””,”NetInput9″:””,”NetInput10″:””,”NetOutSpeed2″:”45561″,”NetOutSpeed3″:”3013176266″,”NetOutSpeed4″:”0″,”NetOutSpeed5″:””,”NetInputSpeed2″:”45561″,”NetInputSpeed3″:”3373591241″,”NetInputSpeed4″:”0″,”NetInputSpeed5″:””})

可以确认,返回的即为包含服务器实时信息的数据。

有没有感觉,在其后的数据有着一种很规范的标记方法?是的,在中括号之间,是一种json数据集。

JSON是一种取代XML的数据结构,和xml相比,它更小巧但描述能力却不差,由于它的小巧所以网络传输数据将减少更多流量从而加快速度。

可以将其理解成一组各类语言都可以接受的,有自己的标准的,用于互相交换信息的数据。

url中的参数 act=rt ,在雅黑PHP探针源码中ctrl+F一下其源代码。

立刻找到,在tz.php中第964行:

//ajax调用实时刷新 if ($_GET[‘act’] == “rt”) { $arr=array(‘useSpace’=>”$du”,’freeSpace’=>”$df”,’hdPercent’=>”$hdPercent”,’barhdPercent’=>”$hdPercent%”,’TotalMemory’=>”$mt”,’UsedMemory’=>”$mu”,’FreeMemory’=>”$mf”,’CachedMemory’=>”$mc”,’Buffers’=>”$mb”,’TotalSwap’=>”$st”,’swapUsed’=>”$su”,’swapFree’=>”$sf”,’loadAvg’=>”$load”,’uptime’=>”$uptime”,’freetime’=>”$freetime”,’bjtime’=>”$bjtime”,’stime’=>”$stime”,’memRealPercent’=>”$memRealPercent”,’memRealUsed’=>”$memRealUsed”,’memRealFree’=>”$memRealFree”,’memPercent’=>”$memPercent%”,’memCachedPercent’=>”$memCachedPercent”,’barmemCachedPercent’=>”$memCachedPercent%”,’swapPercent’=>”$swapPercent”,’barmemRealPercent’=>”$memRealPercent%”,’barswapPercent’=>”$swapPercent%”,’NetOut2’=>”$NetOut[2]”,’NetOut3’=>”$NetOut[3]”,’NetOut4’=>”$NetOut[4]”,’NetOut5’=>”$NetOut[5]”,’NetOut6’=>”$NetOut[6]”,’NetOut7’=>”$NetOut[7]”,’NetOut8’=>”$NetOut[8]”,’NetOut9’=>”$NetOut[9]”,’NetOut10’=>”$NetOut[10]”,’NetInput2’=>”$NetInput[2]”,’NetInput3’=>”$NetInput[3]”,’NetInput4’=>”$NetInput[4]”,’NetInput5’=>”$NetInput[5]”,’NetInput6’=>”$NetInput[6]”,’NetInput7’=>”$NetInput[7]”,’NetInput8’=>”$NetInput[8]”,’NetInput9’=>”$NetInput[9]”,’NetInput10’=>”$NetInput[10]”,’NetOutSpeed2’=>”$NetOutSpeed[2]”,’NetOutSpeed3’=>”$NetOutSpeed[3]”,’NetOutSpeed4’=>”$NetOutSpeed[4]”,’NetOutSpeed5’=>”$NetOutSpeed[5]”,’NetInputSpeed2’=>”$NetInputSpeed[2]”,’NetInputSpeed3’=>”$NetInputSpeed[3]”,’NetInputSpeed4’=>”$NetInputSpeed[4]”,’NetInputSpeed5’=>”$NetInputSpeed[5]”); $jarr=json_encode($arr); $_GET[‘callback’] = htmlspecialchars($_GET[‘callback’]); echo $_GET[‘callback’],'(‘,$jarr,’)’; exit; }

即使不懂PHP,也可以看出它的规则。在我们的url中,callback参数为“jQuery1705809678890101435_1487402170358&_=1487402269387”。尝试直接请求 http://tyo01.misaka.cc:10086/tz.php

得到如下结果:

({“useSpace”:”3.986″,”freeSpace”:”15.576″,”hdPercent”:”20.38″,”barhdPercent”:”20.38%”,”TotalMemory”:”490.23 M”,”UsedMemory”:”414.94 M”,”FreeMemory”:”75.29 M”,”CachedMemory”:”84.82 M”,”Buffers”:”105.35 M”,”TotalSwap”:”0 M”,”swapUsed”:”0 M”,”swapFree”:”0 M”,”loadAvg”:”0.05 0.01 0.00 1\/117″,”uptime”:”3\u59293\u5c0f\u65f644\u5206\u949f”,”freetime”:””,”bjtime”:””,”stime”:”2017-02-18 15:35:36″,”memRealPercent”:”45.85″,”memRealUsed”:”224.77 M”,”memRealFree”:”265.46 M”,”memPercent”:”84.64%”,”memCachedPercent”:”17.3″,”barmemCachedPercent”:”17.3%”,”swapPercent”:”0″,”barmemRealPercent”:”45.85%”,”barswapPercent”:”0%”,”NetOut2″:”44 K 505 B “,”NetOut3”:”2 G 826 M 560 K 68 B “,”NetOut4″:””,”NetOut5″:””,”NetOut6″:””,”NetOut7″:””,”NetOut8″:””,”NetOut9″:””,”NetOut10″:””,”NetInput2″:”44 K 505 B “,”NetInput3”:”3 G 146 M 334 K 784 B “,”NetInput4″:””,”NetInput5″:””,”NetInput6″:””,”NetInput7″:””,”NetInput8″:””,”NetInput9″:””,”NetInput10″:””,”NetOutSpeed2″:”45561″,”NetOutSpeed3″:”3014180932″,”NetOutSpeed4″:”0″,”NetOutSpeed5″:””,”NetInputSpeed2″:”45561″,”NetInputSpeed3″:”3374660368″,”NetInputSpeed4″:”0″,”NetInputSpeed5″:””})

爬虫的思路也清晰了。

2.Python的简单爬虫

Python爬虫的简易教程我参考了:Python爬虫教程

2.1 服务器返回json

文章简洁精悍。没多少字,简单带过后,了解了爬虫运用的一些思想。

想获得服务器信息的json数据,比较容易。现在shell中验证一下

pi@raspberrypi:~ $ python3 Python 3.4.2 (default, Oct 19 2014, 13:31:11) [GCC 4.9.1] on linux Type “help”, “copyright”, “credits” or “license” for more information. >>> from urllib import request >>> f = request.urlopen(“http://138.197.193.89:10086/tz.php?act=rt”) >>> print(f) “http.client.HTTPResponse object at 0x7656ef70” >>> data = f.read() >>> print(data.decode(‘utf-8’))

这里试着直接用我示例站的ip地址,避免等待dns解析。用utf-8格式解码后,得到如下结果:

({“useSpace”:”3.983″,”freeSpace”:”15.579″,”hdPercent”:”20.36″,”barhdPercent”:”20.36%”,”T 0.00 0.00 1\/119″,”uptime”:”3\u59290\u5c0f\u65f616\u5206\u949f”,”freetime”:””,”bjtime”:.49%”,”swapPercent”:”0″,”barmemRealPercent”:”51.14%”,”barswapPercent”:”0%”,”NetOut2″:”4437 M 409 K 258 B “,”NetInput4″:””,”NetInput5″:””,”NetInput6″:””,”NetInput7″:””,”NetInputetInputSpeed4″:”0″,”NetInputSpeed5″:””})

打印出来的字符串并不是标准的json数据,字符串左右多了小括号。使用Python方便的字符串处理功能,将其去掉。但此时data并不是str属性,直接尝试去掉小括号会报错。

此时data的类型为“bytes”。用str()转换:

>>> type(data) “class ‘bytes'” >>> data2 = str(data.decode(‘utf-8’)).strip(‘(‘).strip(‘)’) >>> print(data2) {“useSpace”:”3.983″,”freeSpace”:”15.579″,”hdPercent”:”20.36″,”barhdPercent”:”20.36%”,”TotalMemory”:”490.23 M”,”UsedMemory”:”427.5 M”,”FreeMemory”:”62.73 M”,”CachedMemory”:”76.5 M”,”Buffers”:”98.95 M”,”TotalSwap”:”0 M”,”swapUsed”:”0 M”,”swapFree”:”0 M”,”loadAvg”:”0.00 0.00 0.00 1\/121″,”uptime”:”3\u59290\u5c0f\u65f624\u5206\u949f”,”freetime”:””,”bjtime”:””,”stime”:”2017-02-18 12:15:45″,”memRealPercent”:”51.41″,”memRealUsed”:”252.05 M”,”memRealFree”:”238.18 M”,”memPercent”:”87.2%”,”memCachedPercent”:”15.6″,”barmemCachedPercent”:”15.6%”,”swapPercent”:”0″,”barmemRealPercent”:”51.41%”,”barswapPercent”:”0%”,”NetOut2″:”44 K 505 B “,”NetOut3”:”2 G 817 M 1005 K 862 B “,”NetOut4″:””,”NetOut5″:””,”NetOut6″:””,”NetOut7″:””,”NetOut8″:””,”NetOut9″:””,”NetOut10″:””,”NetInput2″:”44 K 505 B “,”NetInput3”:”3 G 137 M 942 K 336 B “,”NetInput4″:””,”NetInput5″:””,”NetInput6″:””,”NetInput7″:””,”NetInput8″:””,”NetInput9″:””,”NetInput10″:””,”NetOutSpeed2″:”45561″,”NetOutSpeed3″:”3005200222″,”NetOutSpeed4″:”0″,”NetOutSpeed5″:””,”NetInputSpeed2″:”45561″,”NetInputSpeed3″:”3365845328″,”NetInputSpeed4″:”0″,”NetInputSpeed5″:””}

此时data2可直接通过json读取为字典

>>> json.loads(data2) {‘hdPercent’: ‘20.36’, ‘NetInput9’: ”, ‘swapFree’: ‘0 M’, ‘NetOutSpeed5’: ”, ‘UsedMemory’: ‘427.5 M’, ‘NetOut10’: ”, ‘NetInput4’: ”, ‘NetInputSpeed5’: ”, ‘FreeMemory’: ‘62.73 M’, ‘NetInputSpeed4’: ‘0’, ‘NetOut7’: ”, ‘TotalSwap’: ‘0 M’, ‘NetOut2’: ’44 K 505 B ‘, ‘NetOut5’: ”, ‘NetOut8’: ”, ‘NetInput5’: ”, ‘NetOut4’: ”, ‘NetInputSpeed2’: ‘45561’, ‘memCachedPercent’: ‘15.6’, ‘NetInputSpeed3’: ‘3365845328’, ‘loadAvg’: ‘0.00 0.00 0.00 1/121’, ‘TotalMemory’: ‘490.23 M’, ‘barmemRealPercent’: ‘51.41%’, ‘NetOut6’: ”, ‘NetInput7’: ”, ‘barswapPercent’: ‘0%’, ‘NetOutSpeed2’: ‘45561’, ‘barhdPercent’: ‘20.36%’, ‘stime’: ‘2017-02-18 12:15:45’, ‘useSpace’: ‘3.983’, ‘bjtime’: ”, ‘barmemCachedPercent’: ‘15.6%’, ‘memRealFree’: ‘238.18 M’, ‘NetInput3’: ‘3 G 137 M 942 K 336 B ‘, ‘NetInput6’: ”, ‘uptime’: ‘3天0小时24分钟’, ‘NetOutSpeed4’: ‘0’, ‘NetInput2’: ’44 K 505 B ‘, ‘freetime’: ”, ‘NetOut3’: ‘2 G 817 M 1005 K 862 B ‘, ‘NetInput10’: ”, ‘memRealUsed’: ‘252.05 M’, ‘Buffers’: ‘98.95 M’, ‘freeSpace’: ‘15.579’, ‘memPercent’: ‘87.2%’, ‘NetOutSpeed3’: ‘3005200222’, ‘swapUsed’: ‘0 M’, ‘CachedMemory’: ‘76.5 M’, ‘NetOut9’: ”, ‘swapPercent’: ‘0’, ‘memRealPercent’: ‘51.41’, ‘NetInput8’: ”} >>> data3=json.loads(data2) >>> type(data3) “class ‘dict'” >>> type(data3[‘CachedMemory’]) “class ‘str'”

完成。接下来只需要按照面向对象的思想、增加代码的健壮性将其封装起来即可。

2.2 笨拙地封装

用我笨拙的手法尝试封装一下~

# -*- coding:utf-8 -*- from urllib import request import json #探针爬虫类 class PHPTZ: #初始化方法,定义一些变量 def __init__(self): self.url = ‘http://138.197.193.89:888/tz.php?act=rt’ def getData(self): try: f = request.urlopen(self.url) data = f.read() data2 = str(data.decode(‘utf-8’)).strip(‘(‘).strip(‘)’) dataj = json.loads(data2) print(dataj) print(type(dataj)) except print(‘Error’) return None myserver = PHPTZ() myserver.getData()

运行一下:

pi@raspberrypi:~ $ sudo python3 tz.py {‘NetInput7’: ”, ‘NetInput5’: ”, ‘NetOut2’: ’44 K 505 B ‘, ‘uptime’: ‘3天4小时48分钟’, ‘loadAvg’: ‘0.00 0.00 0.00 1/115’, ‘NetInput10’: ”, ‘stime’: ‘2017-02-18 16:39:49’, ‘NetInput4’: ”, ‘NetOutSpeed2’: ‘45561’, ‘NetInputSpeed3’: ‘3379146879’, ‘freetime’: ”, ‘NetOut9’: ”, ‘UsedMemory’: ‘418.66 M’, ‘hdPercent’: ‘20.39’, ‘swapFree’: ‘0 M’, ‘NetOut7’: ”, ‘CachedMemory’: ‘87.81 M’, ‘NetInput3’: ‘3 G 150 M 620 K 127 B ‘, ‘NetOut3’: ‘2 G 830 M 296 K 887 B ‘, ‘NetInputSpeed4’: ‘0’, ‘NetOut6’: ”, ‘NetInput2’: ’44 K 505 B ‘, ‘memRealPercent’: ‘45.61’, ‘FreeMemory’: ‘71.57 M’, ‘NetInput8’: ”, ‘NetOut8’: ”, ‘memRealFree’: ‘266.66 M’, ‘freeSpace’: ‘15.573’, ‘swapPercent’: ‘0’, ‘barmemRealPercent’: ‘45.61%’, ‘memCachedPercent’: ‘17.91’, ‘TotalMemory’: ‘490.23 M’, ‘NetInputSpeed2’: ‘45561’, ‘barmemCachedPercent’: ‘17.91%’, ‘NetInputSpeed5’: ”, ‘TotalSwap’: ‘0 M’, ‘NetOut4’: ”, ‘barhdPercent’: ‘20.39%’, ‘Buffers’: ‘107.28 M’, ‘useSpace’: ‘3.989’, ‘memPercent’: ‘85.4%’, ‘bjtime’: ”, ‘NetOutSpeed4’: ‘0’, ‘NetInput6’: ”, ‘memRealUsed’: ‘223.57 M’, ‘barswapPercent’: ‘0%’, ‘swapUsed’: ‘0 M’, ‘NetOut5’: ”, ‘NetInput9’: ”, ‘NetOutSpeed5’: ”, ‘NetOutSpeed3’: ‘3018105719’, ‘NetOut10’: ”}

确实得到了一个包含数据的字典。

这里注意一下。字典中”speed”的值为一累计数,在后来的数据处理用,需要算出差值,在本机估算网速。

3.使用1602液晶屏

3.1 1602及接口定义

16是指一行显示16个字符,02表示2行。1602是一种非常常见的、在DIY和工业中广泛使用的显示期间。价格低,可以选用各种颜色的背光,字符颜色也是可选的。

这里不是i2c接口的1602显示屏。

1602的引脚定义如下:

VSS,接地 VDD,接5V电源 VO,液晶对比度调节,接电位器中间的引脚 RS,寄存器选择 RW,读写选择 EN,使能信号 D0,数据位0,4位工作模式下不用,不接 D1,数据位1,4位工作模式下不用,不接 D2,数据位2,4位工作模式下不用,不接 D3,数据位3,4位工作模式下不用,不接 D4,数据位4 D5,数据位5 D6,数据位6 D7,数据位7 A,液晶屏背光+,接5V K,液晶屏背光-,接地

3.2 Raspberry Pi 3B 的引脚定义

该图是型号3b的引脚定义图。之前也是图不对被坑了好久。注意在以下Python代码中,接口号码指的是“GPIO”代号。

3.3 Adafruit的charLCD库

Adafruit系列的库是我比较喜欢的库,好用,简洁易懂!

https://github.com/adafruit/Adafruit_Python_CharLCD

下载后在树莓派上安装时,注意:

需要注意python命令默认代表的Python版本号。我的树莓派,“python”这条命令默认指的是Python2。因此,我需要运行

sudo python3 setup.py install

3.4 点亮1602和运行示例代码

来看一下charLCD库的示例代码:

#!/usr/bin/python # Example using a character LCD connected to a Raspberry Pi or BeagleBone Black. import time import Adafruit_CharLCD as LCD # Raspberry Pi pin configuration: lcd_rs = 27 # Note this might need to be changed to 21 for older revision Pi’s. lcd_en = 22 lcd_d4 = 25 lcd_d5 = 24 lcd_d6 = 23 lcd_d7 = 18 lcd_backlight = 4 # BeagleBone Black configuration: # lcd_rs = ‘P8_8’ # lcd_en = ‘P8_10’ # lcd_d4 = ‘P8_18’ # lcd_d5 = ‘P8_16’ # lcd_d6 = ‘P8_14’ # lcd_d7 = ‘P8_12’ # lcd_backlight = ‘P8_7’ # Define LCD column and row size for 16×2 LCD. lcd_columns = 16 lcd_rows = 2 # Alternatively specify a 20×4 LCD. # lcd_columns = 20 # lcd_rows = 4 # Initialize the LCD using the pins above. lcd = LCD.Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, lcd_columns, lcd_rows, lcd_backlight) # Print a two line message lcd.message(‘Hello

world!’) # Wait 5 seconds time.sleep(5.0) # Demo showing the cursor. lcd.clear() lcd.show_cursor(True) lcd.message(‘Show cursor’) time.sleep(5.0) # Demo showing the blinking cursor. lcd.clear() lcd.blink(True) lcd.message(‘Blink cursor’) time.sleep(5.0) # Stop blinking and showing cursor. lcd.show_cursor(False) lcd.blink(False) # Demo scrolling message right/left. lcd.clear() message = ‘Scroll’ lcd.message(message) for i in range(lcd_columns-len(message)): time.sleep(0.5) lcd.move_right() for i in range(lcd_columns-len(message)): time.sleep(0.5) lcd.move_left() # Demo turning backlight off and on. lcd.clear() lcd.message(‘Flash backlight

in 5 seconds…’) time.sleep(5.0) # Turn backlight off. lcd.set_backlight(0) time.sleep(2.0) # Change message. lcd.clear() lcd.message(‘Goodbye!’) # Turn backlight on. lcd.set_backlight(1)

用起来感觉和Arduino一样。

已经很清楚了,主要是注意,数字代表GPIO接口。

ok,我找到正确的GPIO参照图后,成功点亮。

4.最终组合

先贴出来完整代码

from urllib import request import json import time import Adafruit_CharLCD as LCD import math class PHPTZ: def __init__(self): self.url = ‘http://150.95.151.229:8888/tz.php?act=rt’ self.dataj = [] def getData(self): try: f = request.urlopen(self.url) data = f.read() data2 = str(data.decode(‘utf-8’)).strip(‘(‘).strip(‘)’) self.dataj = json.loads(data2) return self.dataj except : print(‘Error’) return None def getSpeed(self): return self.dataj[‘NetOutSpeed3’] class my1602: def __init__(self,a): self.lcd_rs = 27 self.lcd_en = 22 self.lcd_d4 = 25 self.lcd_d5 = 24 self.lcd_d6 = 23 self.lcd_d7 = 18 self.lcd_backlight = 4 self.lcd_columns = 16 self.lcd_rows = 2 self.lcd = LCD.Adafruit_CharLCD(self.lcd_rs, self.lcd_en, self.lcd_d4, self.lcd_d5, self.lcd_d6, self.lcd_d7,self.lcd_columns, self.lcd_rows, self.lcd_backlight) self.dataj = a def display(self,b,d,t): self.dataj = b self.lcd.clear() self.lcd.message(self.dataj[‘NetOut3′]+’

‘+str(“%.3f”%(d/1024/t))+’ KB/s’) #主函数开始,前四行类似于setup myserver = PHPTZ() mylcd = my1602(data) time1 = time.time() speed2=speed1=myserver.getSpeed() #大循环 while(1): data=myserver.getData() speed2=speed1 speed1=myserver.getSpeed() time2=time1 time1=time.time() mylcd.display(data,float(speed1)-float(speed2),float(time1)-float(time2))

主函数,前四行类似于Arduino中的setup(),只运行一次初始化。然后进入大循环。 ?myserver.getSpeed()返回值为字符串,需要转化成float。 计算网速,用了两次time.time获取时间戳,然后再相除换算得到具体网速。鉴于本地和服务器延迟基本稳定,此方法比较准确。 “%.3f”%(d/1024/t) 保留3位小数 面向对象的设计模式意识浅薄,多多包涵

运行,成功!

5.包装及最终效果

包装见:

残念系手工艺人:手把手教你用湿巾盒DIY树莓派外壳

最终效果:

6.结语

假期学了一点点Python,玩了树莓派。在学期初真真正正用树莓派做出了一个符合自己需求的东西。

树莓派真的好玩,我突然发现我对Linux的理解更深了,一些日常操作也不在话下了。

树莓派真好玩儿,您得来一个。

via: 《 No.004 洞察秋毫的观测者——服务器监控助手(基于PHP探针和Raspberry Pi)》

使用树莓派进行简易人脸识别

昨天的晚会让人脸识别又火了,转载一篇来自 CSDN JireRen 的精彩博文,借花献佛给大家一起尝试DIY树莓派上的人脸识别。

使用树莓派2和OpenCV制作一个简易的人脸识别和追踪系统。

所需硬件

需要:树莓派2、Pi Camera

非必须(如果需要追踪人脸运动,需要一个有两个马达的小云台):云台

安装OpenCV

sudo apt-get update sudo apt-get upgrade sudo apt-get install python-opencv

安装PiCamera

由于我没有使用USB摄像头,而是用了特殊的Pi Camera,样子如下图, 所以需要安装PiCamera来控制摄像头。

安装PiCamera:

sudo apt-get install python-pip sudo apt-get install python-dev sudo pip install picamera

至此人脸识别所需要的准备工作已经完成,可以使用下面的演示代码进行测试。

示例代码

Demo.1

第一个演示只使用单核,由于树莓派的性能有限,在只使用一个CPU核心的情况下视频的帧数非常之低,只有5帧左右,效果不太理想, 另外代码中通过Servo Blaster 控制云台的电机,来实现追踪人脸的功能,不过考虑到这个功能不是必须,所以不在此进行介绍。

### Imports ################################################################### from picamera.array import PiRGBArray from picamera import PiCamera import time import cv2 import os ### Setup ##################################################################### # Center coordinates cx = 160 cy = 120 os.system( “echo 0=150 > /dev/servoblaster” ) os.system( “echo 1=150 > /dev/servoblaster” ) xdeg = 150 ydeg = 150 # Setup the camera camera = PiCamera() camera.resolution = ( 320, 240 ) camera.framerate = 60 rawCapture = PiRGBArray( camera, size=( 320, 240 ) ) # Load a cascade file for detecting faces face_cascade = cv2.CascadeClassifier( ‘/home/pi/opencv-2.4.9/data/lbpcascades/lbpcascade_frontalface.xml’ ) t_start = time.time() fps = 0 ### Main ###################################################################### # Capture frames from the camera for frame in camera.capture_continuous( rawCapture, format=”bgr”, use_video_port=True ): image = frame.array # Use the cascade file we loaded to detect faces gray = cv2.cvtColor( image, cv2.COLOR_BGR2GRAY ) faces = face_cascade.detectMultiScale( gray ) print “Found ” + str( len( faces ) ) + ” face(s)” # Draw a rectangle around every face and move the motor towards the face for ( x, y, w, h ) in faces: cv2.rectangle( image, ( x, y ), ( x + w, y + h ), ( 100, 255, 100 ), 2 ) cv2.putText( image, “Face No.” + str( len( faces ) ), ( x, y ), cv2.FONT_HERSHEY_SIMPLEX, 0.5, ( 0, 0, 255 ), 2 ) tx = x + w/2 ty = y + h/2 if ( cx – tx > 10 and xdeg <= 190 ): xdeg += 3 os.system( "echo 0=" + str( xdeg ) + " > /dev/servoblaster” ) elif ( cx – tx < -10 and xdeg >= 110 ): xdeg -= 3 os.system( “echo 0=” + str( xdeg ) + ” > /dev/servoblaster” ) if ( cy – ty > 10 and ydeg >= 110 ): ydeg -= 3 os.system( “echo 1=” + str( ydeg ) + ” > /dev/servoblaster” ) elif ( cy – ty < -10 and ydeg <= 190 ): ydeg += 3 os.system( "echo 1=" + str( ydeg ) + " > /dev/servoblaster” ) # Calculate and show the FPS fps = fps + 1 sfps = fps / ( time.time() – t_start ) cv2.putText( image, “FPS : ” + str( int( sfps ) ), ( 10, 10 ), cv2.FONT_HERSHEY_SIMPLEX, 0.5, ( 0, 0, 255 ), 2 ) # Show the frame cv2.imshow( “Frame”, image ) cv2.waitKey( 1 ) # Clear the stream in preparation for the next frame rawCapture.truncate( 0 )

[WPGP gif_id=”3055″ width=”600″]

另外请注意由于我使用HaarCascade来进行人脸检测, 需要使用到识别人脸的XML,这些人脸识别的XML文件是随着OpenCV一起安装的,不需要额外的安装, 不过当你在自己树莓派上运行时,请注意调整XML文件的路径, 就是调整这一行:

# Load a cascade file for detecting faces face_cascade = cv2.CascadeClassifier( ‘你的XML文件路径’ )

Demo.2

通过同时使用不同的XML文件,可以实现同时识别不同物体的功能,比如下面这段代码可以同时识别人脸和黑色手机,识别手机所需要的XML文件是由Radamés Ajna和Thiago Hersan制作的, 来源在这里。 更进一步的,我们可以根据自己的需要训练自己的Cascade文件,Naotoshi Seo在此处 给出了详细的教程, 比较简易的还有Thorsten Ball的香蕉识别教程。

### Imports ################################################################### from picamera.array import PiRGBArray from picamera import PiCamera import time import cv2 import os import pygame ### Setup ##################################################################### os.putenv(‘SDL_FBDEV’, ‘/dev/fb1’) # Setup the camera camera = PiCamera() camera.resolution = ( 320, 240 ) camera.framerate = 40 rawCapture = PiRGBArray( camera, size=( 320, 240 ) ) # Load the cascade files for detecting faces and phones face_cascade = cv2.CascadeClassifier( ‘/home/pi/opencv-2.4.9/data/lbpcascades/lbpcascade_frontalface.xml’ ) phone_cascade = cv2.CascadeClassifier( ‘cascade.xml’ ) t_start = time.time() fps = 0 ### Main ###################################################################### # Capture frames from the camera for frame in camera.capture_continuous( rawCapture, format=”bgr”, use_video_port=True ): image = frame.array # Look for faces and phones in the image using the loaded cascade file gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray) phones = phone_cascade.detectMultiScale(gray) # Draw a rectangle around every face for (x,y,w,h) in faces: cv2.rectangle( image, ( x, y ), ( x + w, y + h ), ( 255, 255, 0 ), 2 ) cv2.putText( image, “Face No.” + str( len( faces ) ), ( x, y ), cv2.FONT_HERSHEY_SIMPLEX, 0.5, ( 0, 0, 255 ), 2 ) # Draw a rectangle around every phone for (x,y,w,h) in phones: cv2.rectangle( image, ( x, y ), ( x + w, y + h ), ( 255, 0, 0 ), 2 ) cv2.putText( image, “iPhone”, ( x, y ), cv2.FONT_HERSHEY_SIMPLEX, 0.5, ( 0, 255, 255 ), 2 ) # Calculate and show the FPS fps = fps + 1 sfps = fps / ( time.time() – t_start ) cv2.putText( image, “FPS : ” + str( int( sfps ) ), ( 10, 10 ), cv2.FONT_HERSHEY_SIMPLEX, 0.5, ( 0, 0, 255 ), 2 ) cv2.imshow( “Frame”, image ) cv2.waitKey( 1 ) # Clear the stream in preparation for the next frame rawCapture.truncate( 0 )

[WPGP gif_id=”3053″ width=”600″]

由于使用了更多的XML文件进行识别,帧数降低到了2~3帧。

Demo.3

为了解决帧数较低的问题,有一个比较简单的方法就是跳帧,可以不对每一帧图像都进行识别,而是隔几帧识别一次(因为最初因为懒不想将程序写成多线程,但是为了提高帧数,所以有了这个蛋疼的方法…)。

### Imports ################################################################### from picamera.array import PiRGBArray from picamera import PiCamera import time import cv2 import os import pygame ### Setup ##################################################################### os.putenv( ‘SDL_FBDEV’, ‘/dev/fb1’ ) # Setup the camera camera = PiCamera() camera.resolution = ( 320, 240 ) camera.framerate = 30 rawCapture = PiRGBArray( camera, size=( 320, 240 ) ) fcounter = 0 facefind = 0 # Load a cascade file for detecting faces face_cascade = cv2.CascadeClassifier( ‘/home/pi/opencv-2.4.9/data/lbpcascades/lbpcascade_frontalface.xml’ ) t_start = time.time() fps = 0 ### Main ###################################################################### # Capture frames from the camera for frame in camera.capture_continuous( rawCapture, format=”bgr”, use_video_port=True ): image = frame.array # Run the face detection algorithm every four frames if fcounter == 3: fcounter = 0 # Look for faces in the image using the loaded cascade file gray = cv2.cvtColor( image, cv2.COLOR_BGR2GRAY ) faces = face_cascade.detectMultiScale( gray ) print “Found ” + str( len( faces ) ) + ” face(s)” if str( len( faces ) ) != 0: facefind = 1 facess = faces else: facefind = 0 # Draw a rectangle around every face for ( x, y, w, h ) in faces: cv2.rectangle( image, ( x, y ), ( x + w, y + h ), ( 200, 255, 0 ), 2 ) cv2.putText( image, “Face No.” + str( len( facess ) ), ( x, y ), cv2.FONT_HERSHEY_SIMPLEX, 0.5, ( 0, 0, 255 ), 2 ) facess = faces else: if facefind == 1 and str( len( facess ) ) != 0: # Continue to draw the rectangle around every face for ( x, y, w, h ) in facess: cv2.rectangle( image, ( x, y ), ( x + w, y + h ), ( 200, 255, 0 ), 2 ) cv2.putText( image, “Face No.” + str( len( facess ) ), ( x, y ), cv2.FONT_HERSHEY_SIMPLEX, 0.5, ( 0, 0, 255 ), 2 ) fcounter += 1 # Calculate and show the FPS fps = fps + 1 sfps = fps / ( time.time() – t_start ) cv2.putText( image, “FPS : ” + str( int( sfps ) ), ( 10, 10 ), cv2.FONT_HERSHEY_SIMPLEX, 0.5, ( 0, 0, 255 ), 2 ) cv2.imshow( “Frame”, image ) cv2.waitKey( 1 ) # Clear the stream in preparation for the next frame rawCapture.truncate( 0 )

[WPGP gif_id=”3051″ width=”600″]

这样子帧数会提高到10帧左右,已经不像原来那么卡顿,但是当你移动速度很快的时候,识别框会出现滞后。

Demo.4

毕竟跳帧只是权宜之计,这个版本使用了全部的CPU核心,帧数稳定在了15帧左右。

### Imports ################################################################### from picamera.array import PiRGBArray from picamera import PiCamera from functools import partial import multiprocessing as mp import cv2 import os import time ### Setup ##################################################################### os.putenv( ‘SDL_FBDEV’, ‘/dev/fb0’ ) resX = 320 resY = 240 cx = resX / 2 cy = resY / 2 os.system( “echo 0=150 > /dev/servoblaster” ) os.system( “echo 1=150 > /dev/servoblaster” ) xdeg = 150 ydeg = 150 # Setup the camera camera = PiCamera() camera.resolution = ( resX, resY ) camera.framerate = 60 # Use this as our output rawCapture = PiRGBArray( camera, size=( resX, resY ) ) # The face cascade file to be used face_cascade = cv2.CascadeClassifier(‘/home/pi/opencv-2.4.9/data/lbpcascades/lbpcascade_frontalface.xml’) t_start = time.time() fps = 0 ### Helper Functions ########################################################## def get_faces( img ): gray = cv2.cvtColor( img, cv2.COLOR_BGR2GRAY ) faces = face_cascade.detectMultiScale( gray ) return faces, img def draw_frame( img, faces ): global xdeg global ydeg global fps global time_t # Draw a rectangle around every face for ( x, y, w, h ) in faces: cv2.rectangle( img, ( x, y ),( x + w, y + h ), ( 200, 255, 0 ), 2 ) cv2.putText(img, “Face No.” + str( len( faces ) ), ( x, y ), cv2.FONT_HERSHEY_SIMPLEX, 0.5, ( 0, 0, 255 ), 2 ) tx = x + w/2 ty = y + h/2 if ( cx – tx > 15 and xdeg <= 190 ): xdeg += 1 os.system( "echo 0=" + str( xdeg ) + " > /dev/servoblaster” ) elif ( cx – tx < -15 and xdeg >= 110 ): xdeg -= 1 os.system( “echo 0=” + str( xdeg ) + ” > /dev/servoblaster” ) if ( cy – ty > 15 and ydeg >= 110 ): ydeg -= 1 os.system( “echo 1=” + str( ydeg ) + ” > /dev/servoblaster” ) elif ( cy – ty < -15 and ydeg <= 190 ): ydeg += 1 os.system( "echo 1=" + str( ydeg ) + " > /dev/servoblaster” ) # Calculate and show the FPS fps = fps + 1 sfps = fps / (time.time() – t_start) cv2.putText(img, “FPS : ” + str( int( sfps ) ), ( 10, 10 ), cv2.FONT_HERSHEY_SIMPLEX, 0.5, ( 0, 0, 255 ), 2 ) cv2.imshow( “Frame”, img ) cv2.waitKey( 1 ) ### Main ###################################################################### if __name__ == ‘__main__’: pool = mp.Pool( processes=4 ) fcount = 0 camera.capture( rawCapture, format=”bgr” ) r1 = pool.apply_async( get_faces, [ rawCapture.array ] ) r2 = pool.apply_async( get_faces, [ rawCapture.array ] ) r3 = pool.apply_async( get_faces, [ rawCapture.array ] ) r4 = pool.apply_async( get_faces, [ rawCapture.array ] ) f1, i1 = r1.get() f2, i2 = r2.get() f3, i3 = r3.get() f4, i4 = r4.get() rawCapture.truncate( 0 ) for frame in camera.capture_continuous( rawCapture, format=”bgr”, use_video_port=True ): image = frame.array if fcount == 1: r1 = pool.apply_async( get_faces, [ image ] ) f2, i2 = r2.get() draw_frame( i2, f2 ) elif fcount == 2: r2 = pool.apply_async( get_faces, [ image ] ) f3, i3 = r3.get() draw_frame( i3, f3 ) elif fcount == 3: r3 = pool.apply_async( get_faces, [ image ] ) f4, i4 = r4.get() draw_frame( i4, f4 ) elif fcount == 4: r4 = pool.apply_async( get_faces, [ image ] ) f1, i1 = r1.get() draw_frame( i1, f1 ) fcount = 0 fcount += 1 rawCapture.truncate( 0 )

帧数上升到了13左右,而且识别框没有延迟。

[WPGP gif_id=”3048″ width=”600″]

Demo.5

搞定了低帧数问题,我又试了试多核加跳帧…帧数可到28帧左右。

### Imports ################################################################### from picamera.array import PiRGBArray from picamera import PiCamera from functools import partial import multiprocessing as mp import cv2 import os ### Setup ##################################################################### os.putenv( ‘SDL_FBDEV’, ‘/dev/fb0’ ) resX = 320 resY = 240 # Setup the camera camera = PiCamera() camera.resolution = ( resX, resY ) camera.framerate = 90 t_start = time.time() fps = 0 # Use this as our output rawCapture = PiRGBArray( camera, size=( resX, resY ) ) # The face cascade file to be used face_cascade = cv2.CascadeClassifier( ‘/home/pi/opencv-2.4.9/data/lbpcascades/lbpcascade_frontalface.xml’ ) ### Helper Functions ########################################################## def get_faces( img ): gray = cv2.cvtColor( img, cv2.COLOR_BGR2GRAY ) return face_cascade.detectMultiScale( gray ), img def draw_frame( img, faces ): global fps global time_t # Draw a rectangle around every face for ( x, y, w, h ) in faces: cv2.rectangle( img, ( x, y ),( x + w, y + h ), ( 200, 255, 0 ), 2 ) # Calculate and show the FPS fps = fps + 1 sfps = fps / (time.time() – t_start) cv2.putText(img, “FPS : ” + str( int( sfps ) ), ( 10, 10 ), cv2.FONT_HERSHEY_SIMPLEX, 0.5, ( 0, 0, 255 ), 2 ) cv2.imshow( “Frame”, img ) cv2.waitKey( 1 ) ### Main ###################################################################### if __name__ == ‘__main__’: pool = mp.Pool( processes=4 ) i = 0 rList = [None] * 17 fList = [None] * 17 iList = [None] * 17 camera.capture( rawCapture, format=”bgr” ) for x in range ( 17 ): rList[x] = pool.apply_async( get_faces, [ rawCapture.array ] ) fList[x], iList[x] = rList[x].get() fList[x] = [] rawCapture.truncate( 0 ) for frame in camera.capture_continuous( rawCapture, format=”bgr”, use_video_port=True ): image = frame.array if i == 1: rList[1] = pool.apply_async( get_faces, [ image ] ) draw_frame( iList[2], fList[1] ) elif i == 2: iList[2] = image draw_frame( iList[3], fList[1] ) elif i == 3: iList[3] = image draw_frame( iList[4], fList[1] ) elif i == 4: iList[4] = image fList[5], iList[5] = rList[5].get() draw_frame( iList[5], fList[5] ) elif i == 5: rList[5] = pool.apply_async( get_faces, [ image ] ) draw_frame( iList[6], fList[5] ) elif i == 6: iList[6] = image draw_frame( iList[7], fList[5] ) elif i == 7: iList[7] = image draw_frame( iList[8], fList[5] ) elif i == 8: iList[8] = image fList[9], iList[9] = rList[9].get() draw_frame( iList[9], fList[9] ) elif i == 9: rList[9] = pool.apply_async( get_faces, [ image ] ) draw_frame( iList[10], fList[9] ) elif i == 10: iList[10] = image draw_frame( iList[11], fList[9] ) elif i == 11: iList[11] = image draw_frame( iList[12], fList[9] ) elif i == 12: iList[12] = image fList[13], iList[13] = rList[13].get() draw_frame( iList[13], fList[13] ) elif i == 13: rList[13] = pool.apply_async( get_faces, [ image ] ) draw_frame( iList[14], fList[13] ) elif i == 14: iList[14] = image draw_frame( iList[15], fList[13] ) elif i == 15: iList[15] = image draw_frame( iList[16], fList[13] ) elif i == 16: iList[16] = image fList[1], iList[1] = rList[1].get() draw_frame( iList[1], fList[1] ) i = 0 i += 1 rawCapture.truncate( 0 )

[WPGP gif_id=”3047″ width=”600″]

跳帧加多核,强行30帧哈哈,不过还是建议最终使用Demo4。

这篇博客节选翻译自我自己的课程报告, 同样的内容也出现于我自己的英文博客, 最后出镜的是我的搭档Andre Heil。

via 转自 JireRen 的博客。