树莓派上搭建自己的 python 开发环境

一般情况下,在烧录完镜像以后就可以直接在树莓派上通过 thony idle 去进行 python 的开发了.

但是用惯了 pycharm 和习惯了 vim 编程的我怎么可以直接用文本编辑器写代码呢?

效率完全没有了啊!

安装完镜像环境后,就可以在树莓派上开发了,为了开发opencv for python,我在树莓派上搭建了vim的python开发环境,除了配置.vimrc以外还要给各位小伙伴安利一款VIM python 自动补全插件:pydiction。

这是在纯shell环境下进行python编程的一款利器, 全屏编辑器结合这款利器各种 python 补全不再是问题。
pydiction可以实现下面python代码的自动补全:

简单python关键词补全
python 函数补全带括号
python 模块补全
python 模块内函数,变量补全
from module import sub-module 补全


  1. 安装 vim

sudo apt-get  update

sudo apt-get -y install vim git

2. 下载插件

mkdir -p ~/.vim/bundle

cd ~/.vim/bundle

git clone https://github.com/rkulla/pydiction.git

3. 配置~/.vimrc

vim ~/.vimrc

4. 在配置文件最下面填写

#载入文件类型插件

filetype plugin on

#配置插件路径

let g:pydiction_location = ‘~/.vim/bundle/pydiction/complete-dict’

#设置补全菜单的高度

let g:pydiction_menu_height = 3

然后就可以通过 vim 进行代码编写了.这时候就有了自动补全的功能.

#配色方案(可用 :highlight 查看配色方案细节)

colorscheme murphy

#打开语法高亮

syntax on

#侦测文件类型

filetype on

#载入文件类型插件

filetype plugin on

#为不同文件类型使用不用缩进

filetype indent on

#显示行号

set number

#打开自动缩进

set autoindent

#使用 C/C++ 的缩进方式

set cindent

#为 C 程序提供自动缩进

set smartindent

#设置自动缩进长度为四个空格

set shiftwidth=4

#按退格键时可以一次删掉 4 个空格

set softtabstop=4

#设定 tab 键长度为 4

set tabstop=4

#将 tab 展开为空格

set expandtab

#去掉输入错误时的提示声音

set noerrorbells

#右下角显示光标位置

set ruler

#总是显示状态行

set laststatus=2

#自定义状态行
set statusline=%F%m%r%h%w[%L][%{&ff}]%y[%p%%][%04l,%04v]

#当前列数+当前行数+当前光标位置百分比+使用的语法高亮器+文件格式+文件总行数+预览标志+帮助文件标志+只读标志+已修改标志+当前文件绝对路径

#强调匹配的括号

set showmatch

#光标短暂跳转到匹配括号的时间, 单位是十分之一秒

set matchtime=2

#显示当前正在键入的命令

set showcmd

# 设置自动切换目录为当前文件所在目录,用 :sh 时候会很方便

set autochdir

# 搜索时忽略大小写

set ignorecase

#随着键入即时搜索

set incsearch

#有一个或以上大写字母时仍大小写敏感

set smartcase

#代码折叠

set foldenable

set foldmethod=indent

#在左侧显示折叠的层次

set foldcolumn=4

#针对 Python 文件的设定

if has(“autocmd”)

autocmd FileType python set tabstop=4 shiftwidth=4 expandtab

endif

#配置pydiction插件路径

let g:pydiction_location = ‘/home/pi/.vim/bundle/pydiction/complete-dict’

#设置pydiction补全菜单的高度

let g:pydiction_menu_height = 3

希望对大家有用,谢谢!

利用树莓派和官方摄像头实现延时摄影

最近看了一个朋友用树莓派做的延时视频,感觉挺不错的,突然也想做一个. 手头正好有树莓派和摄像头,所以也尝试着做了一下,非常简单.

首先说明一下什么是延时摄影:

要创建延时视频,只需将Raspberry Pi配置为定期拍摄照片(例如每分钟),然后使用应用程序将图片拼接成视频。原理就这么简单.

有两种方法可以做到这一点。如果是官方摄像头,实现起来就更加简单了.

使用Raspistill的内置延时模式

raspistill应用程序具有内置的延时模式,使用--timelapse(或-tl)命令行开关。

切换之后的值是拍摄之间的时间(以毫秒为单位)。

raspistill -t 30000 -tl 2000 -o image%04d.jpg

请注意%04d输出文件名中的数字:这表示文件名中要显示照片编号。因此,例如,上面的命令将每隔两秒(2000毫秒)产生一次照片的捕获,总时间为30秒(30000毫秒),名为image0001.jpg,image0002.jpg,依此类推,直到image0015.jpg。

%04d指示四位数字,有前导零添加,以弥补所需的位数。因此,例如,%08d会产生一个八位数的数字。0 这个位,如果你不想要前导零,你可以不加。

如果输入的- t 为0,则应用程序将以其最小时间间隔进行拍摄照片。请注意,捕获之间存在大约30毫秒的最小强制暂停,以确保可以进行曝光计算。

使用cron(计划任务)

使用自定义拍照的好方法是使用cron

打开cron 表进行编辑:

crontab -e

这将询问您要使用哪个编辑器,或者在默认编辑器中打开。在编辑器中打开文件后,添加以下行以安排每分钟拍照.

camera.sh 可以自己写个拍摄的脚本,其中2>&1是将错误输出输入到标准输出上.

* * * * * /home/pi/camera.sh 2>&1

保存并退出,您应该看到以下消息:

crontab: installing new crontab

确保您的脚本不保存使用相同文件名拍摄的每张照片。否则将每次覆盖原有的图片。

将图像拼接在一起

现在,您需要将照片拼接成一个视频。

你可以在Pi上使用,mencoder非常赞, 但处理速度很慢。也可以将图像文件传输到台式计算机或笔记本电脑并在那里处理视频,那样会快一些,因为如果你拍摄了24小时的图片,每小时的每分钟拍摄5张图片的话,数据量也是大的惊人的.处理起来也是时间更长.但是如果在树莓派上通过脚本自行处理了,最后得到的视频就可以直接播放了. 如果你会推流处理,那还可以直接推到直播平台. 也是很好的.

切换到包含所有图像的文件夹,并将文件名重定向到一个文本文件。例如:

ls *.jpg > pics.list

在RASPBERRY PI上

虽然速度很慢(由于使用软件进行编码而不是使用Raspberry Pi硬件加速),但您可以使用各种可用工具将JPEG图像拼接在一起。其中有个软件叫avconv,需要安装, 安装好以后就可以拼接转码了。

sudo apt-get install libav-tools

现在,可以使用这些工具将JPEG文件转换为H264格式的视频文件。

avconv -r 24 -i image%04d.jpg -r 24 -vcodec libx264 -vf scale=800:480 timelapse.mp4

在Raspberry Pi 3上,它可以每秒编码多于一帧。其他Pi型号的性能会有所不同.

目前我这边使用的参数是:

  • -r 24在输入和输出文件中假设每秒二十四帧。
  • -i image%04.jpg输入文件规范(用于匹配捕获期间生成的文件)。
  • -vcodec libx264使用软件x264编码器进行编码。
  • -vf scale = 800:480  调整为输出720p。您还可以使用1920:1080或更低分辨率,具体取决于你自己的要求, 例如,我是要在52pi.taobao.com 买的800×480分辨率。请注意,Pi只能播放高达1080p的视频,但如果您打算以4K播放,则可以在此设置。
  • timelapse.mp4输出文件的名称。

avconv具有针对不同编码选项和其他设置的综合参数集。这些可以使用列出avconv --help

在另一台LINUX计算机上

您可以使用与Raspberry Pi相同的说明,或者替代包,例如mencoder

sudo apt-get install mencoder

现在运行以下命令:

mencoder -nosound -ovc lavc -lavcopts vcodec=mpeg4:aspect=16/9:vbitrate=8000000 -vf scale=1920:1080 -o timelapse.avi -mf type=jpeg:fps=24 mf://@pics.list

一旦完成,您应该有一个视频文件,timelapse.avi

然后你就可以用播放器播放查看了.

omxplayer -o hdmi  timelapse.avi

效果是不是杠杠滴?

树莓派官方镜像更新-新特性解说

树莓派官方放出了最新的镜像版本为2018-06-17, 新版本的发布一般情况下会有一些软件的更新, bug 的修复等等, 我们来一起看看这款新版本的更新更新了什么内容:
1.  添加了新的启动配置向导, 真正实现了傻瓜化的配置道路…
设置国家
设置用户的密码
选择 wifi 网络.
检查更新
安装更新
配置完成后重启.
2. 添加了推荐软件安装器
3. Bluej, Greenfoot, NodeRED, Claws Mail, VNC Viewer 已经被从镜像移除, 可以通过推荐应用进行安装.
4. Qpdfview PDF viewer 集成在系统中用来取代Xpdf, 看 PDF 更加给力了!
5. 系统原生包含Version 65.0 的Chromium浏览器, 并支持最新的 Flash 播放器,意味着如果看优酷视频也不会因为播放器不兼容而不好用了, 系统烧录完直接打开浏览器就看世界杯了.
 
6. 音量的调节可以以5%的幅度进行增减了, 并且可以选择输出设备了.
7. 网络的插件可以对以前输入过的网络密码进行记忆了, 当重连的时候会提示密码信息.方便了不少.
8. 串口和串口控制台能够在树莓派配置中进行切换.
9. Lxkeymap 键盘语言设置移除 – 替换为在 Raspberry Pi Configuration的对话设置中了.
10.  Wifi 国家及键盘语言设置对话框可以被其他应用调用了,就意味着如果其他的应用程序需要修改语言或者键盘映射类型就可以直接调用管理控制台完成设置了.

11. 新版本的PiBOTO字体包括在某些恶意应用程序中以正确的权重渲染.

12. 在重新启动时,自动重新连接到蓝牙音频设备. 你如果有蓝牙音箱的应用就非常舒服了.

13. 如果选择了”单击启用” ,请在文件管理器中”禁用单击以重命名文件”

14. “外观设置对话框”对某些QT文件进行配置更改,以匹配选定主题.

15. 改进的MIME文件类型关联

16. 多个桌面管理选项取消了鼠标中键作用.

17. 修改了树莓派Pi网站的菜单快捷方式,使得访问更加清晰,帮助就是帮助,项目就是项目.一目了然.

18. 删除了Python 2 idle 的菜单链接,看来要全面支持 python3了.

19. MAGPI PDF安装在/home /pi/MagPi 中, 更加方便查看 magpi 杂志.

20. 应用各种小调整、错误修复和外观更改

21. 蓝牙更新, 连接速度更快更有效.并且具有蓝牙4.2特性的固件,虽然我的蓝牙无法支持4.2, 但是固件升级了肯定增加很多新特性.

22.通过bthelper.serivce添加了对 SCO 配置的支持.

23. 内核方面的升级: Linux内核4.1450+

Raspberry Pi固件78FB1799 2426BB29 D9224B93CB962FEFBDC833

更多新特性等待你起来尝试! 快点去下载新镜像来武装你的树莓派吧!!!

 

Pi Zero Enc28j60网络适配器模块使用说明 SKU:EP-0088

Pi Zero Enc28j60网络适配器模块使用说明

说明

对于Pi Zero来说, 如果没有网卡是非常不方便的,因为它的核心系统是Linux,
大多数操作都是基于linux的命令行通过ssh服务来完成的.所以它其实需要一个网络适配器,也就是我们常说的网卡, Pi zero enc28j60是简单网络适配器模块,它非常易于组装和配置。
它允许您的Raspberry Pi zero 顺利访问网络,这样就可以很容易进行系统更新和软件安装操作。

兼容性列表

  • 兼容性
平台 版本1.01(HW V1.01) 备注
Raspberry Pi 3 Model B Plus
树莓派零
Raspberry Pi零W
Raspberry Pi 3型号B.
树莓派2型号B
树莓派模型B +

功能

  • 易于组装
  • 易于设置
  • 官方OS覆盖支持
  • 稳定而快速
  • 重量:0.015Kg
  • 尺寸:65.14mm x 29.93mm x 23.34mm

装配展示:

如何配置:

  • 1.将NIC模块安装到raspberry Pi中。
  • 2.连接好网线以确保您的路由器支持DHCP并且运行良好。

  • 3.将Raspbian镜像文件烧录到TF卡。
  • 4.使用您喜欢的编辑器(如“nano”或“vim.tiny”)编辑/boot/config.txt文件,并添加以下参数:
dtoverlay=enc28j60

然后保存退出并重新启动raspberry Pi。
注意:该模块仅在raspbian操作系统环境中进行测试。

如何检查网络适配器是否正常工作

打开终端并输入以下命令:

ifconfig

您将看到Pi zero Enc28j60网络适配器模块的详细信息.这时候说明网卡可以正常使用了.

同时你会看到屏幕右上方的网络连接图标已经呈现出一上一下一对箭头.

套件组件包括:

  • Pi零点Enc28j60网络适配器模块x 1
  • 说明x 1

更多内容请关注www.52pi.net,您将获得更多好玩儿有趣的资讯!

 

树莓派使用 USB 麦克风录音

前几天,有朋友从我们淘宝店买了USB 接口的麦克风, 说是无法识别, 没办法录音, 经过交流发现, 实际上是咩有开启麦克风的音量.

这篇帖子简单介绍一下怎么去利用 usb 麦克风录音,更多应用在后面给大家拓展一下.

首先这个麦克风,超级小巧和物美价廉.哈哈10元你买不了吃亏买不了上当…

 

接驳的方式很简单, 麦克风接入树莓派的 USB 口,然后启动树莓派, 这里我说的直接启动是在假设你已经通过烧录工具烧录好了操作系统.目前操作环境使用的是 Raspbian 系统.

可以去官方下载: http://www.raspberrypi.org/downloads

我这里测试环境是树莓派3B+, 8GBTF 卡.

然后登陆系统,打开终端, 输入如下命令检查是否识别出了 USB 设备.

第一个是我的2.4Ghz 的无线键鼠, 第二个就是麦克风的设备了.

也可以通过 dmesg 看看:

可以看到已经检测到 PnP Sound Device.

接下来,我们看看使用什么方式去录音.你可以安装 ALSA 的录音应用软件:

安装软件前先升级或者说更新一下软件仓库的索引信息: sudo apt-get update

然后执行安装:

sudo apt-get -y  install  alsa-utils   pulseseaudio

然后直接输入:

arecord  -L

就列出目前你机器上可以用的声卡了.

然后可以通过:

arecord –device=hw:1,0 –format S16_LE –rate 44100 -c1 test.wav

说明一下: –device=hw:1,0 是定义录音的设备. –format S16_LE 是定义 signed 16-bit (S16_LE) 音频. 码率是: 44100 Hz (--rate 44100) 后面的参数是定义为mono 格式 (-c1) , 文件名为: test.wav

这里的录音设备1,0 是因为系统设别出来的状态决定的, subdevices 是1, subdevice是0.

来吼一曲一人我饮酒醉, 然后录音录下来,播放看看效果如何.

可以按下 ctrl+C 终止.

如果想播放看看效果:

aplay –device=plughw:1,0 test.wav

之前我们提到了,如果麦克风音量没有开,可能会录出来的内容是无声的.

因此可以通过 alsamixer 去调整, 这里- c 1 是设置输入输出都在一个设置层面上,就是可以在一个终端中通过面板操作所有的音频设备:

alsamixer -c 1

默认为00,按F5的上就可以看到这样的画面:

Mic 就是麦克风了,现在音量很低,你需要按上调试合适的音量.

按 Tab 键可以切换调试的设备.

按 ESC 退出.

再执行录音就可以了.

后面和语音相关的应用介绍:

可以通过命令录音,然后上传给百度语音识别的 API 接口,通过百度语音识别后, 生成 Text 文本,然后将 text 文本提交到图灵机器人后台的 API, 可以得到图灵机器人的反馈,也应该是文本,然后再将文本转语音,就是传说中的 TTS, 那样,你的树莓派就可以和天猫精灵,小米智能音响一样和你交互了.

快去试试看吧!

 

[树莓派官方新闻] 与绿海龟和ARRIBADA主动性一起旅行

今天,一个客座教授:Alasdair Davies,ZSL伦敦保护技术专家,Shuttleworth基金会研究员Naturebytes的共同创始人,分享了Arribada Initiative的工作。该项目使用树莓派零相机模块来跟随绿海龟的旅程。从这些宏伟的生物背面拍摄的画面是不可思议的 ~
小编独白: 海龟背上一个小小的 RPi zero 带着电池,还有一个摄像头,要一个防水外壳之类,全部加起来估计要500g 了, 要找大海龟才行.

在动物跟踪世界中获得价格合理,开放和可定制的保护技术往往是有限的。过去十年来,我一直是一名环保技术专家,共同创立Naturebytes,并在ZSL伦敦动物园工作,这是一个令我感到困扰的问题。收集必要的有价值的数据是非常昂贵的,这些数据是通报政策,指定海洋保护区或查明对物种的威胁所必需的。

今年3月,我获得了一个超级机会,成为沙特尔沃思基金会的成员,突破了这些障碍,这意味着我有时间和资源集中精力解决问题。该Arribada倡议成立,10个月后,开源Arribada PS-C绿海龟标签诞生。上面的视频是在两周前在西非普林西比岛的水域拍摄的。

View image on TwitterView image on TwitterView image on Twitter

该电子标签包含一个覆盖树莓派摄像头模块的Raspberry Pi Zero W,一个PiRA电源管理板,两个锂离子电池以及一个相当不错的外壳。它与Institute IRNAS一起建造,并且有一个不错的用户友好的无线充电箱,以便海员在海上航行后更换电子标签。当标签返回到案例中的一个坞站时,我们使用resin.io来管理它,下载视频,并远程配置电子标签。

电子标签还可以配置为定时拍摄视频剪辑,这意味着我们现在可以观察海洋垃圾,塑料碎片,由于附近的建筑,污染和其他威胁而导致的海洋环境变化之前/之后的情况。

被丢弃的渔网对海龟是致命的,所以使用这个新的电子标签 – 现在终于可能了,因为Raspberry Pi Zero有助于大幅度降低成本,同时保持出色的视频质量 – 为该领域的科学家提供了真正的价值。明年,我们将发布一个优化的,经济实惠的GPS版本。

绿海龟Alasdair戴维斯树莓派Arribada倡议

为了使这一切成为可能,我们必须设计一种将电子标签贴在海龟身上的更快速的方法,所以我们想出了“加油站”技术(这就是PS名为“Arribada PS-C”的站点对于)。就像一辆一级方程式赛车参观赛车轮胎的轮胎,当海龟返回沙滩时,我们会在海滩上切换电子标签,用快速释放的底板代替全新的电子标签。

为了实施该系统,我们首先将底板粘贴到海龟壳上(用的是环氧树脂,就是我们常说的502吧~),这使得尽可能快地减少对海龟的带来的任何压力。一旦环氧树脂(520胶)干了,我们贴上电子标签。当龟已经完成了排卵周期(他们在一个季节里每次下蛋三到四次,平均每10到14天下一次),我们只需要移除底盘即可完成采集的任务。

结束语:  看来我们还在摸索如何做更好玩儿的东西的时候, 这些科学家已经用树莓派做了太多关于生物,海洋, 生态的研究的设备了. 我们还需要努力啊~

使用MQTT连接树莓派IoT设备

有时候,你可能会发现自己处于一种你想让设备通过互联网相互通信的情况。例如,当我到另一个城市旅行的时候,我意识到我忘了关掉我房间的灯光。在这种情况下,我希望有一个Android应用程序或一个网站,我可以监视我家的灯光状态,并能打开或关闭它们。

所以,假设你想在一个可以在世界任何地方操作的房间里连接一个电灯开关。一个快速而稳定的选项是使用MQTT。

什么是MQTT?

MQTT(消息队列遥测传输)是一种轻量级消息传递协议,非常适用于物联网连接设备的通信。

MQTT有三个组件:代理,发布者和订阅者。经纪人是处理设备之间进行通信的中介实体。发布者是发送消息的设备。订阅者收听发布者发送的消息。

在MQTT中还有一件更重要的事情,那就是一个话题。不同设备之间的通信需要一个主题。例如,设备A想要向设备B发送消息。为此,两者之间应该有一些共同之处,那就是主题。把它想象成一个电话号码。

CloudMQTT

CloudMQTT是为特定数量的设备提供免费MQTT通信的代理服务。

设置MQTT

  • 在“名称”字段中输入CMQTT

  • 点击创建
  • 记下您的数据,如下图所示

 

 

  • 在同一页面上,在管理用户中添加一个用户:
    • 名字:pi
    • 密码:pi

 

  • 点击“保存”
  • 再次在最后的同一页上:
    • 用户:pi
    • 主题:pi

 

  • 并点击“保存”
  • 现在,在顶部的栏中,点击“WebSocket UI”

 

 

  • 你会看到一个页面,所有的传感器数据将被显示
  • 将以下代码上传到Arduino

下面的代码是用虚拟字符串代替传感器的示例代码。您可以用来自传感器的值替换字符串。

String sensorsData=""; 
String randSensorsData=""; 
void setup() {
   // put your setup code here, to run once: 
Serial.begin(9600); 
pinMode(A0,INPUT);//temperature sensor 
pinMode(A1,INPUT);//windspeed sensor 
pinMode(A2,INPUT);//wind direction sensor 
pinMode(A3,INPUT);//rain fall sensor 
pinMode(A4,INPUT);///barometric pressure sensor
} 

void loop() {
   // put your main code here, to run repeatedly:      
sensorsData=String("-")+String("S1=")+String(analogRead(A0))+String(",")+String("S2=")+String(analogRead(A1))+ \
String(",")+String("S3=")+String(analogRead(A2))+String(",")+String("S4=")+  \
String(analogRead(A3))+String(",")+String("S5=")+String(analogRead(A4))+String("+");     
randSensorsData=String("-")+String("S1=")+String(random(100))+String(",")+String("S2=")+ \
String(random(200))+String(",")+String("S3=")+String(random(125))+String(",")+String("S4=")+\
String(random(500))+String(",")+String("S5=")+String(random(50))+String("+");     
   Serial.println(sensorsData);     
   Serial.println(randSensorsData);   
   delay(200); 
}

此代码使用Arduino的模拟引脚来获取传感器的值,并传递到Raspberry Pi进行处理和MQTT通信。上面的代码使用随机函数来生成随机值来模拟模拟引脚。

  • 传感器应连接到A0,A1,A2,A3,A4引脚,
  • Serial.println(randSensorsData);
  • 这一行发送随机数据来检查服务器。
  • 您也可以检查在WebSocket UI中显示的随机数据。
  • 打开python 2.7并在其中编写下面的代码:
import paho.mqtt.client as mqtt
import time
data=”Hello from Raspberry Pi!”
while True:
    print(data)
    try:
        client=mqtt.Client()
        client.username_pw_set("yoyojacky","MyRPiPr0J")#替换成你的用户名和密码
        client.connect("m13.cloudmqtt.com",13017,60)
        client.publish("pi",data) #这里的 pi 是你的话题,客户端就订阅这个话题
        time.sleep(1)
    except KeyboardInterrupt:
        print("end")
        client.disconnect()
  • 现在使用python 2.7运行代码
  • 您将在每秒钟后看到传感器数据显示在CloudMQTT的WebScoket UI中。

  • 在这里,您将看到从Raspberry Pi发送的数据。

令人惊讶的是,CloudMQTT提供了一个完整的dashboard用于测试目的。您可以使用此dashboard订阅或发布主题.

在接下来就可以去配置你的 arduino 和树莓派来管理家里的设备或者查询家里的设备信息了!

 

[找回失落的记忆]树莓派+Pygame模块编写俄罗斯方块

昨天晚上,在家整理东西的时候, 突然翻找出来很早以前小时候的 Gameboy(可能不是这个名字了), 装电池的那种,很古老,只有一款游戏就是俄罗斯方块, 突然回忆就拉回了小学时代和同学一起比拼俄罗斯方块分数的日子,每天都无忧无虑的,不用考虑房贷,车保险….然后突然有一个想法,为什么不用树莓派做一个游戏机呢? 网上教程一堆一堆的, 都是用 retropie, lakka之类的系统实现一个模拟器的平台, 我觉得不够极客, 如果自己用 python 写一个游戏不是更好? 又能巩固 python 的代码能力,又可以让树莓派一机多用, 不仅只是个游戏机, 还可以是下载器,gitlab, 或者是一个 OSMC, 家庭媒体中心呢?

翻找了一下我的 Maker 材料箱, 找到一个吃灰已久的树莓派3B, 通过官方下载全新的镜像,然后烧录系统, 更新系统,配置 ssh, 配置主机名,配置字符集,配置 IP 地址等等一系列操作后. 利用 python 命令执行一下看看版本信息:

$ python -V
Python 2.7.10

就用默认版本吧, 然后去检查一下 pygame 的状态,默认情况下, pygame 已经集成在系统里面了, 如果没有要去官方站点上下载一下并安装, 连接如下: http://pygame.org/wiki/tutorials,官方的这个链接上已经说明:http://pygame.org/wiki/GettingStarted#Raspberry PI

Raspberry PI

This comes with pygame already installed on the default raspberian installation.

那么接下来的事儿就简单多了. 下面是我准备的材料:

  1. 树莓派3 B 型  x1
  2. 16GB class 10 的 TF 卡一张, 最好有SD 卡套方便进行系统烧录
  3. 5v2.5A 电源一套,为了方便,我这里采用的是52Pi 官方的 USB-HUB, 专为树莓派设计, 购买点我
  4. 5寸电阻触摸屏( GPIO 引脚控制), 购买点我 
  5. 外壳你可以自己 DIY 或者利用以下链接下载 STL 文件然后转码成 Gcode 交给3D 打印机打印.3D打印外壳链接

好了,我要开始操作了,首先你要做的事儿是把设备接驳起来,像这样:

然后启动后配置好网络后执行我写好的脚本就可以进行分辨率调节:

git clone https://github.com/yoyojacky/52Pi.git

cd ~/52Pi/

chmod +x restool.sh

sudo ./restool.sh

然后重启, 屏幕的分辨率和电容触摸的驱动就加载好了.

后面需要执行屏幕校准:

cd ~/52Pi/

chmod +x calibrator.sh

sudo ./calibrator.sh

基本配置告一段落了,然后检查 pygame 的版本:

pip list

或者通过 python 的 IDE 直接进行查询,在终端键入python 然后回车继续输入如下 python 代码:

 import  pygame

pygame.ver

看到如下图示:

说明pygame 的模块已经安装过,系统中包含这个模块了,就可以开始下面的操作了.

然后创建一个目录:

mkdir -pv  /home/pi/mygame/music

sudo vim.tiny  /home/pi/mygame/russianblock.py

我一次性创建了一个目录结构, mygame 目录下面创建一个 python 文件, 名字为: russianblock.py

然后可以两首 MP3的歌曲进去, 也可以直接下载我提供的素材:

Have A Drink On Me,Rolling in the Deep

然后继续添加如下python 代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import random, time, pygame, sys
from pygame.locals import *

FPS = 25
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
BOXSIZE = 20
BOARDWIDTH = 10
BOARDHEIGHT = 20
BLANK = '.'

MOVESIDEWAYSFREQ = 0.15
MOVEDOWNFREQ = 0.1

XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2)
TOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5
#        R  G  B
WHITE    = (255, 255, 255)
GRAY    = (185, 185, 185)
BLACK    = ( 0,  0,  0)
RED     = (155,  0,  0)
LIGHTRED  = (175, 20, 20)
GREEN    = ( 0, 155,  0)
LIGHTGREEN = ( 20, 175, 20)
BLUE    = ( 0,  0, 155)
LIGHTBLUE  = ( 20, 20, 175)
YELLOW   = (155, 155,  0)
LIGHTYELLOW = (175, 175, 20)

BORDERCOLOR = BLUE
BGCOLOR = BLACK
TEXTCOLOR = WHITE
TEXTSHADOWCOLOR = GRAY
COLORS   = (   BLUE,   GREEN,   RED,   YELLOW)
LIGHTCOLORS = (LIGHTBLUE, LIGHTGREEN, LIGHTRED, LIGHTYELLOW)
assert len(COLORS) == len(LIGHTCOLORS) # each color must have light color

TEMPLATEWIDTH = 5
TEMPLATEHEIGHT = 5

S_SHAPE_TEMPLATE = [['.....',
           '.....',
           '..OO.',
           '.OO..',
           '.....'],
          ['.....',
           '..O..',
           '..OO.',
           '...O.',
           '.....']]

Z_SHAPE_TEMPLATE = [['.....',
           '.....',
           '.OO..',
           '..OO.',
           '.....'],
          ['.....',
           '..O..',
           '.OO..',
           '.O...',
           '.....']]

I_SHAPE_TEMPLATE = [['..O..',
           '..O..',
           '..O..',
           '..O..',
           '.....'],
          ['.....',
           '.....',
           'OOOO.',
           '.....',
           '.....']]

O_SHAPE_TEMPLATE = [['.....',
           '.....',
           '.OO..',
           '.OO..',
           '.....']]

J_SHAPE_TEMPLATE = [['.....',
           '.O...',
           '.OOO.',
           '.....',
           '.....'],
          ['.....',
           '..OO.',
           '..O..',
           '..O..',
           '.....'],
          ['.....',
           '.....',
           '.OOO.',
           '...O.',
           '.....'],
          ['.....',
           '..O..',
           '..O..',
           '.OO..',
           '.....']]

L_SHAPE_TEMPLATE = [['.....',
           '...O.',
           '.OOO.',
           '.....',
           '.....'],
          ['.....',
           '..O..',
           '..O..',
           '..OO.',
           '.....'],
          ['.....',
           '.....',
           '.OOO.',
           '.O...',
           '.....'],
          ['.....',
           '.OO..',
           '..O..',
           '..O..',
           '.....']]

T_SHAPE_TEMPLATE = [['.....',
           '..O..',
           '.OOO.',
           '.....',
           '.....'],
          ['.....',
           '..O..',
           '..OO.',
           '..O..',
           '.....'],
          ['.....',
           '.....',
           '.OOO.',
           '..O..',
           '.....'],
          ['.....',
           '..O..',
           '.OO..',
           '..O..',
           '.....']]

PIECES = {'S': S_SHAPE_TEMPLATE,
     'Z': Z_SHAPE_TEMPLATE,
     'J': J_SHAPE_TEMPLATE,
     'L': L_SHAPE_TEMPLATE,
     'I': I_SHAPE_TEMPLATE,
     'O': O_SHAPE_TEMPLATE,
     'T': T_SHAPE_TEMPLATE}


def main():
  global FPSCLOCK, DISPLAYSURF, BASICFONT, BIGFONT
  pygame.init()
  FPSCLOCK = pygame.time.Clock()
  DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
  BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
  BIGFONT = pygame.font.Font('freesansbold.ttf', 100)
  pygame.display.set_caption('Tetromino')

  showTextScreen('YoYoJacky')
  while True: # game loop
    if random.randint(0, 1) == 0:
      pygame.mixer.music.load('music/Have A Drink On Me.mp3')
    else:
      pygame.mixer.music.load('music/Rolling In The Deep.mp3')
    pygame.mixer.music.play(-1, 0.0)
    runGame()
    pygame.mixer.music.stop()
    showTextScreen('Game Over')


def runGame():
  # setup variables for the start of the game
  board = getBlankBoard()
  lastMoveDownTime = time.time()
  lastMoveSidewaysTime = time.time()
  lastFallTime = time.time()
  movingDown = False # note: there is no movingUp variable
  movingLeft = False
  movingRight = False
  score = 0
  level, fallFreq = calculateLevelAndFallFreq(score)

  fallingPiece = getNewPiece()
  nextPiece = getNewPiece()

  while True: # game loop
    if fallingPiece == None:
      # No falling piece in play, so start a new piece at the top
      fallingPiece = nextPiece
      nextPiece = getNewPiece()
      lastFallTime = time.time() # reset lastFallTime

      if not isValidPosition(board, fallingPiece):
        return # can't fit a new piece on the board, so game over

    checkForQuit()
    for event in pygame.event.get(): # event handling loop
      if event.type == KEYUP:
        if (event.key == K_p):
          # Pausing the game
          DISPLAYSURF.fill(BGCOLOR)
          pygame.mixer.music.stop()
          showTextScreen('Paused') # pause until a key press
          pygame.mixer.music.play(-1, 0.0)
          lastFallTime = time.time()
          lastMoveDownTime = time.time()
          lastMoveSidewaysTime = time.time()
        elif (event.key == K_LEFT or event.key == K_a):
          movingLeft = False
        elif (event.key == K_RIGHT or event.key == K_d):
          movingRight = False
        elif (event.key == K_DOWN or event.key == K_s):
          movingDown = False

      elif event.type == KEYDOWN:
        # moving the piece sideways
        if (event.key == K_LEFT or event.key == K_a) and isValidPosition(board, fallingPiece, adjX=-1):
          fallingPiece['x'] -= 1
          movingLeft = True
          movingRight = False
          lastMoveSidewaysTime = time.time()

        elif (event.key == K_RIGHT or event.key == K_d) and isValidPosition(board, fallingPiece, adjX=1):
          fallingPiece['x'] += 1
          movingRight = True
          movingLeft = False
          lastMoveSidewaysTime = time.time()

        # rotating the piece (if there is room to rotate)
        elif (event.key == K_UP or event.key == K_w):
          fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])
          if not isValidPosition(board, fallingPiece):
            fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
        elif (event.key == K_q): # rotate the other direction
          fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
          if not isValidPosition(board, fallingPiece):
            fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])

        # making the piece fall faster with the down key
        elif (event.key == K_DOWN or event.key == K_s):
          movingDown = True
          if isValidPosition(board, fallingPiece, adjY=1):
            fallingPiece['y'] += 1
          lastMoveDownTime = time.time()

        # move the current piece all the way down
        elif event.key == K_SPACE:
          movingDown = False
          movingLeft = False
          movingRight = False
          for i in range(1, BOARDHEIGHT):
            if not isValidPosition(board, fallingPiece, adjY=i):
              break
          fallingPiece['y'] += i - 1

    # handle moving the piece because of user input
    if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ:
      if movingLeft and isValidPosition(board, fallingPiece, adjX=-1):
        fallingPiece['x'] -= 1
      elif movingRight and isValidPosition(board, fallingPiece, adjX=1):
        fallingPiece['x'] += 1
      lastMoveSidewaysTime = time.time()

    if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1):
      fallingPiece['y'] += 1
      lastMoveDownTime = time.time()

    # let the piece fall if it is time to fall
    if time.time() - lastFallTime > fallFreq:
      # see if the piece has landed
      if not isValidPosition(board, fallingPiece, adjY=1):
        # falling piece has landed, set it on the board
        addToBoard(board, fallingPiece)
        score += removeCompleteLines(board)
        level, fallFreq = calculateLevelAndFallFreq(score)
        fallingPiece = None
      else:
        # piece did not land, just move the piece down
        fallingPiece['y'] += 1
        lastFallTime = time.time()

    # drawing everything on the screen
    DISPLAYSURF.fill(BGCOLOR)
    drawBoard(board)
    drawStatus(score, level)
    drawNextPiece(nextPiece)
    if fallingPiece != None:
      drawPiece(fallingPiece)

    pygame.display.update()
    FPSCLOCK.tick(FPS)


def makeTextObjs(text, font, color):
  surf = font.render(text, True, color)
  return surf, surf.get_rect()


def terminate():
  pygame.quit()
  sys.exit()


def checkForKeyPress():
  # Go through event queue looking for a KEYUP event.
  # Grab KEYDOWN events to remove them from the event queue.
  checkForQuit()

  for event in pygame.event.get([KEYDOWN, KEYUP]):
    if event.type == KEYDOWN:
      continue
    return event.key
  return None


def showTextScreen(text):
  # This function displays large text in the
  # center of the screen until a key is pressed.
  # Draw the text drop shadow
  titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTSHADOWCOLOR)
  titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2))
  DISPLAYSURF.blit(titleSurf, titleRect)

  # Draw the text
  titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR)
  titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3)
  DISPLAYSURF.blit(titleSurf, titleRect)

  # Draw the additional "Press a key to play." text.
  pressKeySurf, pressKeyRect = makeTextObjs('Press a key to play.', BASICFONT, TEXTCOLOR)
  pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100)
  DISPLAYSURF.blit(pressKeySurf, pressKeyRect)

  while checkForKeyPress() == None:
    pygame.display.update()
    FPSCLOCK.tick()


def checkForQuit():
  for event in pygame.event.get(QUIT): # get all the QUIT events
    terminate() # terminate if any QUIT events are present
  for event in pygame.event.get(KEYUP): # get all the KEYUP events
    if event.key == K_ESCAPE:
      terminate() # terminate if the KEYUP event was for the Esc key
    pygame.event.post(event) # put the other KEYUP event objects back


def calculateLevelAndFallFreq(score):
  # Based on the score, return the level the player is on and
  # how many seconds pass until a falling piece falls one space.
  level = int(score / 10) + 1
  fallFreq = 0.27 - (level * 0.02)
  return level, fallFreq

def getNewPiece():
  # return a random new piece in a random rotation and color
  shape = random.choice(list(PIECES.keys()))
  newPiece = {'shape': shape,
        'rotation': random.randint(0, len(PIECES[shape]) - 1),
        'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2),
        'y': -2, # start it above the board (i.e. less than 0)
        'color': random.randint(0, len(COLORS)-1)}
  return newPiece


def addToBoard(board, piece):
  # fill in the board based on piece's location, shape, and rotation
  for x in range(TEMPLATEWIDTH):
    for y in range(TEMPLATEHEIGHT):
      if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK:
        board[x + piece['x']][y + piece['y']] = piece['color']


def getBlankBoard():
  # create and return a new blank board data structure
  board = []
  for i in range(BOARDWIDTH):
    board.append([BLANK] * BOARDHEIGHT)
  return board


def isOnBoard(x, y):
  return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT


def isValidPosition(board, piece, adjX=0, adjY=0):
  # Return True if the piece is within the board and not colliding
  for x in range(TEMPLATEWIDTH):
    for y in range(TEMPLATEHEIGHT):
      isAboveBoard = y + piece['y'] + adjY < 0
      if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK:
        continue
      if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY):
        return False
      if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK:
        return False
  return True

def isCompleteLine(board, y):
  # Return True if the line filled with boxes with no gaps.
  for x in range(BOARDWIDTH):
    if board[x][y] == BLANK:
      return False
  return True


def removeCompleteLines(board):
  # Remove any completed lines on the board, move everything above them down, and return the number of complete lines.
  numLinesRemoved = 0
  y = BOARDHEIGHT - 1 # start y at the bottom of the board
  while y >= 0:
    if isCompleteLine(board, y):
      # Remove the line and pull boxes down by one line.
      for pullDownY in range(y, 0, -1):
        for x in range(BOARDWIDTH):
          board[x][pullDownY] = board[x][pullDownY-1]
      # Set very top line to blank.
      for x in range(BOARDWIDTH):
        board[x][0] = BLANK
      numLinesRemoved += 1
      # Note on the next iteration of the loop, y is the same.
      # This is so that if the line that was pulled down is also
      # complete, it will be removed.
    else:
      y -= 1 # move on to check next row up
  return numLinesRemoved


def convertToPixelCoords(boxx, boxy):
  # Convert the given xy coordinates of the board to xy
  # coordinates of the location on the screen.
  return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE))


def drawBox(boxx, boxy, color, pixelx=None, pixely=None):
  # draw a single box (each tetromino piece has four boxes)
  # at xy coordinates on the board. Or, if pixelx & pixely
  # are specified, draw to the pixel coordinates stored in
  # pixelx & pixely (this is used for the "Next" piece).
  if color == BLANK:
    return
  if pixelx == None and pixely == None:
    pixelx, pixely = convertToPixelCoords(boxx, boxy)
  pygame.draw.rect(DISPLAYSURF, COLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1))
  pygame.draw.rect(DISPLAYSURF, LIGHTCOLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 4, BOXSIZE - 4))


def drawBoard(board):
  # draw the border around the board
  pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5)

  # fill the background of the board
  pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT))
  # draw the individual boxes on the board
  for x in range(BOARDWIDTH):
    for y in range(BOARDHEIGHT):
      drawBox(x, y, board[x][y])


def drawStatus(score, level):
  # draw the score text
  scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR)
  scoreRect = scoreSurf.get_rect()
  scoreRect.topleft = (WINDOWWIDTH - 150, 20)
  DISPLAYSURF.blit(scoreSurf, scoreRect)

  # draw the level text
  levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR)
  levelRect = levelSurf.get_rect()
  levelRect.topleft = (WINDOWWIDTH - 150, 50)
  DISPLAYSURF.blit(levelSurf, levelRect)


def drawPiece(piece, pixelx=None, pixely=None):
  shapeToDraw = PIECES[piece['shape']][piece['rotation']]
  if pixelx == None and pixely == None:
    # if pixelx & pixely hasn't been specified, use the location stored in the piece data structure
    pixelx, pixely = convertToPixelCoords(piece['x'], piece['y'])

  # draw each of the boxes that make up the piece
  for x in range(TEMPLATEWIDTH):
    for y in range(TEMPLATEHEIGHT):
      if shapeToDraw[y][x] != BLANK:
        drawBox(None, None, piece['color'], pixelx + (x * BOXSIZE), pixely + (y * BOXSIZE))


def drawNextPiece(piece):
  # draw the "next" text
  nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR)
  nextRect = nextSurf.get_rect()
  nextRect.topleft = (WINDOWWIDTH - 120, 80)
  DISPLAYSURF.blit(nextSurf, nextRect)
  # draw the "next" piece
  drawPiece(piece, pixelx=WINDOWWIDTH-120, pixely=100)


if __name__ == '__main__':
  main()

写好以后,先用命令执行测试一下:

sudo python russianblock.py

执行结果看到如下内容就说明成功了:

随便按一个键就可以开始玩儿了,使用键盘的上下左右控制移动, 用空格控制反转,记得把你的耳机插入树莓派3.5mm 的音频复合接口, 然后开始享受游戏的乐趣吧!

如果失败,音乐就停啦!

好了! 这个简单的教程就写到这里, 后期教大家利用 pygame 和树莓派制作更多的好玩儿的小游戏!

Raspbian 有多少个版本?

Raspbian究竟有多少个版本呢,答案是总共有6个版本,其中2个是公开版本,4个是非公开版本.

六个版本,依次增加功能:

1)最小化启动:这其实只是一个引导系统.树莓派专用的一些软件(闭源)会在这个包提供,但是这个系统并不能直接启动.

2)真正最小系统,这就是一个最小最小的系统,只有基础功能,没有任何额外添加.

3)(公开发布)轻量系统,也就是Raspbian-Lite,官方发布的Raspbian-Lite也就是这个系统.

4)基本桌面环境,只有桌面环境但是没有相对应的一些软件.适合于只要桌面但是不需要任何额外软件的用户.

5)用户友好的桌面环境,这个已经非常接近官方发布的系统了,他对用户友好,对新手来说也很方便.并且,这个系统限定在4G卡也可以使用.

6)(公开发布)完整系统,这个就是官方发布Raspbian,也是我们最常用的,他加入了Mathematica软件,其他跟第五个系统是一样的.

制作这些系统可以通过官方Git工具制作,至于公开发布的系统,直接下载就可以了.

https://github.com/RPi-Distro/pi-gen

当然,如果不知道怎么生成其他系统,可以持续关注树莓派中文站,我们将持续有新资料发布,包括这些系统哦.