借助树莓派模拟Wimonitor并实现WiFi窃听和嗅探

Wimonitor是一款非常优秀的黑客工具,它不仅可以帮渗透测试人员省去配置虚拟机和无线网卡等一系列麻烦事,而且它的Web接口配置起来也非常的方便。实际上,它就是一款TP-Link-MR3020路由器,只不过它使用的是自定义固件,并能够将监控到的网络数据包转发给主机电脑(Mac或Windows等主机),而我们此时就可以使用WireShark来对数据包进行分析了。

但是,我们可不可以使用树莓派来实现一样的功能呢?答案当然是肯定的,因此在这篇文章中,我们将教会大家如何使用树莓派3B来搭建一个稳定的WiFi监控平台,并通过几个简单的步骤来将其模拟成一个Wimonitor。

硬件要求

1.      运行Windows的笔记本电脑(测试设备使用的是Windows 8.1)

2.      树莓派3B、Micro SD卡、电源适配器(USB 3.0足够驱动树莓派+无线网卡了)

3.      网线(连接树莓派和笔记本电脑)

4.      支持监听模式的无线网卡(例如TL-WN722N v1)

安装配置

首先,将RASPBIAN STRETCH LITE刻到Micro SD卡中,这是一个轻量级操作系统,并且支持例如TL-WN722N之类的无线网卡,具体的步骤请参考【操作指南】。

刻录完成之后,我们可以通过在SD卡中创建一个名叫ssh的空文件(无需文件扩展名)来启用树莓派的SSH功能。

为了确保笔记本电脑能够跟Pi正常通信,最简单的方法就是用笔记本给Pi共享WiFi,这样就可以保证Pi的IP地址在192.168.137.x范围内。进入网络连接设置(ncap.cpl),右键点击Wi-Fi适配器,然后选择属性。在“Sharing”标签页中,选择需要插入Pi的以太网适配器,点击OK。

接下来,将Pi与笔记本主机连接,然后把SD卡插到Pi的卡槽中,将无线网卡插入到USB端口连接网线(笔记本主机-Pi),然后启动设备。

当Pi启动之后,它将会使用共享链接的IP地址,你可以在笔记本主机上使用nmap(对192.168.137.1/24子网进行主机搜搜)来查看Pi的IP地址。

打开PuTTY,然后使用ssh登录到Pi,我们所使用的Raspbian操作系统默认的用户名和密码分别为pi和raspberry。

给Pi设置一个静态地址,打开/etc/dhcpcd.conf并将下列代码添加到文件末尾:

interfaceeth0
staticip_address=192.168.137.100/24
staticrouters=192.168.137.1
staticdomain_name_servers=192.168.137.1

我个人比较喜欢使用基于密钥的SSH登录验证。打开PuTTYgen,然后生成一个密钥对。

在Pi的home目录中创建一个.ssh文件夹,然后在这个文件夹中创建一个名叫authorized_keys的文件,将PuTTYgen生成的公钥复制到这个文件中,最后自己保存好PuTTYgen生成的私钥,并重启Pi的SSH服务。结束之后,别忘了修改Pi的默认密码。

Raspbian操作系统没有自带与网络监控有关的数据包,因此你可以使用下列命令来安装这些包:

sudo apt update 
sudo apt install aircrack-ng tcpdump -y

接下来,我们需要在Pi上测试无线网卡的监听功能是否正常。

既然我们已经验证了Pi能够正常进行网络监控了,我们就可以使用SSH登录到Pi,然后在Pi上运行rcpdump,并将信息转发给运行在笔记本主机中的Wireshark。

plink.exe是PuTTY.exe的Windows命令行接口,为了方便起见,我把plink.exe和PuTTYgen生成的SSH私钥放在了同一个文件夹中。如果这些文件不在同一文件夹中,你就需要相应地修改下列代码中的路径了:

plink.exe-ssh -i pi-monitor-ssh-key.ppk pi@192.168.137.234 "sudo tcpdump -niwlan1mon -s 0 -w -" | "C:\Program Files\Wireshark\Wireshark.exe"-k -i -

如果你只想监听信道1,你可以使用下列命令:

sudo iwconfig wlan1mon channel 1

下面的命令可以开启Pi无线网卡的监听模式:

plink.exe-ssh -i pi-monitor-ssh-key.ppk pi@192.168.137.100 "sudo airmon-ng startwlan1"

接下来,我们可以在笔记本主机中开启Wireshark并开始监听无线网络数据:

plink.exe-ssh -i pi-monitor-ssh-key.ppk pi@192.168.137.100 "sudo tcpdump -niwlan1mon -s 0 -w -" | "C:\Program Files\Wireshark\Wireshark.exe"-k -i -

OK,一切搞定!大家快去自己动手尝试一下吧!

转载自FreeBuf.COM

 

 

 

使用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 和树莓派来管理家里的设备或者查询家里的设备信息了!

 

如何使用树莓派自制网络监视器

本文所介绍的工具适合家庭环境下的“黑盒测试”,它可以帮助你记录网络中发生的所有事情。你可以用它来检测网络威胁,或将数据提供给相关专家来进行网络取证分析。

购物清单

1.      树莓派3 (外壳+电源+电路板)

2.      闪迪Class 10 microSD卡 64GB(80Mb/s)

3.      Debian OS-Linux RaspbianLite

4.      网件千兆交换机或其他支持端口镜像的设备,我使用的是D-Link1100-08P

5.      Critical Stack API(Threat Intel/ IOCs)

6.      Mailgun账号或类似支持警报/通知的邮件服务

概览图

关键技术介绍

什么是端口镜像?

将一个端口的流量数据复制到另一个端口(被动式),会增加交换机的运行负荷。

什么是Bro

一款IDS协议分析工具,你可以把它当作Wireshark的协议分析器,但是它没有GUI界面,而且速度更快。

什么是Netsniff?

进行数据包捕获的守护进程,它使用了AF-packet来提升数据包的捕捉速度。

什么是LOKI

基于YARA的文件扫描守护进程。有些类似基于签名检测的反病毒产品,但是你可以自行制定检测规则。

什么是Critical Stack

一个威胁情报平台,你可以在树莓派上通过API来与该平台链接。

什么是Team Cymru MHR

一个恶意软件哈希库,你可以使用该数据库中的信息来对检测到的恶意程序哈希进行匹配。

开始动手

1.      把系统刷到树莓派中

2.      给树莓派分配一个IP

3.      运行bash脚本

4.      搞定

 

一、把Raspbian刷到microSD卡中

我使用的是MacBook,所以不同平台的方法可能会有所不同,其他平台用户可以参考【这篇教程】来获取更多内容。

插入microSD卡:

diskutil <span class="hljs-built_in">list</span>

找到磁盘号:

diskutil unmountDisk /dev/disk<disk#from diskutil>

将Raspbian镜像刷入到microSD卡’disk’中:

sudo dd bs=<span class="hljs-number">1</span>m <span class="hljs-keyword">if</span>=image.imgof=<span class="hljs-regexp">/dev/rdisk</span><disk<span class="hljs-comment"># from diskutil></span>

完成之后,卸载microSD卡:

diskutil unmountDisk <span class="hljs-meta-keyword">/dev/</span>disk<span class="hljs-params"><disk#from diskutil></span>

二、配置网络

使用默认配置登录。用户名:pi,密码:raspberry。

设置wlan0(wifi)的IP,用于受信管理访问:

sudo nano<span class="hljs-meta-keyword">/etc/</span>wpa_supplicant/wpa_supplicant.conf
network={

ssid="The_ESSID_from_earlier"

psk="Your_wifi_password"

}
sudo ifdown wlan0

sudo ifup wlan0

ifconfig wlan0

当你获取到了一个DHCP IP之后,你可以使用SSH访问这个节点了。接下来,将eth0留下当作镜像接口,它不需要设置IP地址。

sudo apt-get update && sudo apt-get-y install vim

sudo vim /etc/network/interfaces

添加下列代码:

iface eth0 inet static

static ip_address=0.0.0.0

重启eth0接口:

<span class="hljs-attribute">sudo</span> ifconfig eth0 down && sudoifconfig eth0 up

三、部署

下载并运行bash脚本,脚本已在Raspbian上成功测试。

-安装程序的核心组件

-配置网络选项(禁用NIC offloading)

-给每一个程序创建服务

-使用Mailgun/SSMTP创建邮件警报

-配置cron任务

pi@foxhound:~# sudo su -

root@foxhound:~# apt-get install -y git

root@foxhound:~# cd ~

root@foxhound:~# git clonehttps://github.com/sneakymonk3y/foxhound-nsm.git

root@foxhound:~# chmod +xfoxhound-nsm/foxhound.sh

root@foxhound:~# ./foxhound-nsm/foxhound.sh

现在,环境部署已经完全完成啦!

接下来呢?当脚本完成运行之后,所有的服务都会被立刻激活,然后你就可以看到所有流入的数据啦!

性能

通过pcap数据来向镜像端口eth0发送一些垃圾信息,我使用的是一些提前准备好的数据:

pi@foxhound:~ $ sudo tcpreplay -t -K -q--loop=10 --intf1=eth0 /opt/foxhound-1476541443.pcap<br><br>Actual: 1048570 packets (1050923190 bytes)sent in 87.62 seconds. Rated:11994102.0 bps, 91.51 Mbps, 11967.25 pps

下面是发送前和发送后的broctl netstats数据:

root@foxhound:/etc/network# broctl netstats
bro: 1476547903.768150 recvd=1951368 dropped=5408 link=1956776
root@foxhound:/etc/network# broctl netstats
bro: 1476548144.248161 recvd=3012168 dropped=14608 link=3026776

对于家庭或实验室环境来说,它的性能相对还算很好了(1000000个数据包只会丢弃10000个)。我的带宽速度为40Mbps,对于IDS系统来说已经足够了。如果你还需要提升性能,建议考虑换掉树莓派。

如果你想进行更多的NIC perf测试,你可以在服务器上运行下列命令:

mark@ubuntu:~$ sudo apt install iperf3

mark@ubuntu:~$ iperf3 -s

-----------------------------------------------------------

Serverlistening on 5201

然后在树莓派上运行:

root@foxhound:~# apt install iperf3

root@foxhound:~# iperf3 -c 10.0.0.7 -i 1 -t20

Connecting to host 10.0.0.7, port 5201

[ 4]local 10.0.0.180 port 38562 connected to 10.0.0.7 port 5201

[ ID] Interval Transfer Bandwidth Retr Cwnd

[ 4] 0.00-1.00 sec 8.86 MBytes 74.3 Mbits/sec 0 89.1 KBytes

...

...

...

[ 4] 19.00-20.00 sec 9.26 MBytes 77.7 Mbits/sec 0 1.23 MBytes

- - - - - - - - - - - - - - - - - - - - - -- - -

[ ID] Interval Transfer Bandwidth Retr

[ 4] 0.00-20.00 sec 185 MBytes 77.5 Mbits/sec 139 sender

[ 4] 0.00-20.00 sec 184 MBytes 77.1 Mbits/sec receiver

iperf Done.

我假设这里的瓶颈是microSD卡,它的速度大约是80MB/s。

Bro基础

-所有Bro日志的默认存储路径为/nsm/bro/logs/

-默认的脚本路径为/usr/local/bro/share/bro/site/bro-scripts/

日志目录结构大致如下所示:

pi@foxhound:/nsm/bro/logs/current $ ls-lash

total 6.9M

4.0K drwxr-xr-x 3 root root 4.0K Oct 15 16:11 .

4.0K drwxr-xr-x 5 root staff 4.0K Oct 1516:50 ..

4.0K -rw-r--r-- 1 root root 349 Oct 15 16:51 app_stats.log

4.0K -rw-r--r-- 1 root root 121 Oct 15 15:51 .cmdline

16K-rw-r--r-- 1 root root 14K Oct 15 16:30communication.log

2.9M -rw-r--r-- 1 root root 2.9M Oct 15 16:52 conn.log

16K-rw-r--r-- 1 root root 14K Oct 15 16:52dhcp.log

384K -rw-r--r-- 1 root root 379K Oct 15 16:52 dns.log

4.0K -rw-r--r-- 1 root root 345 Oct 15 15:51 .env_vars

1.2M -rw-r--r-- 1 root root 1.2M Oct 15 16:52 files.log

1.6M -rw-r--r-- 1 root root 1.6M Oct 15 16:52 http.log

4.0K -rw-r--r-- 1 root root 291 Oct 15 16:44 known_hosts.log

4.0K -rw-r--r-- 1 root root 327 Oct 15 16:34 known_services.log

12K-rw-r--r-- 1 root root 11K Oct 15 16:50notice.log

4.0K -rw-r--r-- 1 root root 5 Oct 15 15:51 .pid

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.communication

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.conn

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:01 .rotated.conn-summary

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.dhcp

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.dns

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.files

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.http

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.known_hosts

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.known_services

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.loaded_scripts

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.notice

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.packet_filter

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.software

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.ssl

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.weird

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.x509

4.0K -rw-r--r-- 1 root root 3.0K Oct 15 16:51 software.log

320K -rw-r--r-- 1 root root 314K Oct 15 16:52 ssl.log

4.0K -rw-r--r-- 1 root root 58 Oct 15 15:51 .startup

4.0K drwx------ 3 root root 4.0K Oct 15 15:51 .state

4.0K -rwx------ 1 root root 18 Oct 15 15:51 .status

4.0K -rw-r--r-- 1 root root 46Oct 15 15:51 stderr.log

4.0K -rw-r--r-- 1 root root 188 Oct 15 15:51 stdout.log

24K-rw-r--r-- 1 root root 17K Oct 15 16:52weird.log

416K -rw-r--r-- 1 root root 412K Oct 15 16:52 x509.log

你可以使用head命令来查找文本域名称:

pi@foxhound:$ head dns.log<br><br>#separator \x09<br><br>#set_separator ,<br><br>#empty_field (empty)<br><br>#unset_field -<br><br>#path dns<br><br>#open 2016-10-15-16-00-01<br><br>#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto trans_id query qclass qclass_name qtype qtype_name rcode rcode_name AA TC RD RA Z answers TTLs rejected<br><br>#types time string addr port addr port enum count string count string count string count string bool bool bool bool count vector[string] vector[interval] bool

使用bro-cut来解析日志:

pi@foxhound:$ cat dns.log | bro-cut -D tsid.orig_h <span class="hljs-keyword">id</span>.orig_p <span class="hljs-keyword">id</span>.resp_h <span class="hljs-keyword">id</span>.resp_p proto query answers TTLs

基础报告:

pi@foxhound:$ bro-cut query < dns.<span class="hljs-keyword">log</span> |<span class="hljs-keyword">sort</span> | uniq -c | <span class="hljs-keyword">sort</span> -rn | head -n <span class="hljs-number">10</span>

如果你还需要更多的示例,你可以查看Bro提供的官方练习【传送门】。

你可以使用tail命令输出DNS日志并在客户端生成一些DNS流量:

<span class="hljs-attribute">tail</span> -f dns.log | awk  <span class="hljs-string">'{print <span class="hljs-variable">$3</span>, <span class="hljs-variable">$7</span>, <span class="hljs-variable">$9</span>}'</span>

请注意,只有conn.log才可以启用MaxMind GEOIP查询。

pi@foxhound:$ bro-cut resp_cc < conn.log| sort | uniq -c | sort -rn | head -n 10<br><br>755 US<br><br>524 RO<br><br>123 GB<br><br>49 NL<br><br>28 EU<br><br>25 IE<br><br>10 DE<br><br>7 ES<br><br>6 CA

我还没有制作仪表盘(Dashboard),如果你不想自己做的话,你可以直接使用VPS ELK实例在云端存储所有的日志,或者你也可以使用ELK/Splunk/Graylog将日志存储在本地。

基础维护

开启/停止netsniff-ng:

pi@foxhound:~ $ sudo service netsniff-ngstop<br><br>pi@foxhound:~ $ sudo service netsniff-ngstart<br><br>pi@foxhound:~ $ sudo service netsniff-ngstatus

开启/停止bro(网络统计):

pi@foxhound:~ $ sudo -i broctl stop<br><br>pi@foxhound:~ $ sudo -i broctl start<br><br>pi@foxhound:~ $ sudo -i broctl netstats<br><br>pi@foxhound:~ $ sudo -i broctl status

手动运行Loki:

root@foxhound:~ $ python /nsm/Loki/loki.py--noprocscan --dontwait --onlyrelevant -p /nsm/bro/extracted -l /nsm/Loki/log

检测CriticalStack的入侵威胁指标(IoCs),可通过cron脚本实现定期检查:

root@foxhound:~ $ sudo -u critical-stackcritical-stack-intel list

 

参考资料

1.      部署网络安全监控:http://www.appliednsm.com/

2.      网络安全监控实践:https://www.nostarch.com/nsm

3.      Laika BOSS-对象扫描系统:https://github.com/lmco/laikaboss

4.      PassiveDNS:https://github.com/gamelinux/passivedns

5.      D3js(图形化工具):https://d3js.org/

6.      Graylog:https://www.graylog.org/

FB小编Alpha_h4ck编译,转载来自FreeBuf.COM

[找回失落的记忆]树莓派+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 和树莓派制作更多的好玩儿的小游戏!

用树莓派做 RTMP 流直播服务器,可推送至斗鱼直播

在《用树莓派DIY共享鱼缸,支持微信远程喂鱼》一文中,使用了树莓派来做直播服务器。通过安装在树莓派上的摄像头采集实时视频数据流,推送至 RTMP 监听服务器。同时,其他的客户端访问这个 RTMP 服务器就可以观看视频了。下面我们来详细介绍这个模块如何搭建,文末还将给出将直播视频推送至斗鱼直播平台的方法。

需要用的东西和软件说明:

树莓派主板(本文使用树莓派 Zero W 套件,该套件附带一款完美安装摄像头的外壳)
兼容摄像头(本文使用官方摄像头模块,其他 USB 兼容摄像头亦可)
软件方面:
avconv 和 GStreamer 用于采集摄像头捕获的视频流并推送到 RTMP 服务
NGINX 和 RTMP 模块,用于接收视频流,同时提供视频发布功能
Strobe Media Playback,一款基于 Flash 的网页视频播放器

一、配置摄像头

无论是树莓派官方摄像头模块还是其他兼容的USB摄像头,连接好摄像头之后,运行命令去启用摄像头:

sudo raspi-config

编辑系统模块文件。

sudo nano/etc/modules

在这个文件的最后添加一行

bcm2835-v4l2

保存。建议配置好之后重启一下树莓派。然后测试摄像头是否正常工作。

vcgencmd get_camera

输出如图所示表示被识别到。进一步测试拍照。

raspistill -t 2000 -o 1.jpg

执行上面的指令之后,会你用摄像头拍照,并将照片保存在当前目录下,名为 1.jpg。

如果一切正常,恭喜!可以开始下面的步骤了!

二、网络配置

如果你的树莓派使用有线网络的话可以忽略这一步。笔者用的树莓派是 Zero W 版本,没有有线网口,所以必须手动配置无线网络。

sudo nano/etc/network/interfaces

将配置修改为:

auto lo

iface lo inet loopback

allow-hotplug wlan0

auto wlan0

iface wlan0 inet dhcp

        wpa-ssid "WIFISSID"

        wpa-psk "WIFIPASSWORD"

WIFISSID 和 WIFIPASSWORD 分别替换为你的 WIFI 的 SSID 和密码。

网络配置方法可以参考树莓派实验室的其他文章,例如这篇《树莓派 Raspberry Pi 设置无线上网》。

三、安装 NGINX 和 RTMP

我们用 nginx 加上 nginx-rtmp-module 模块作为 RTMP 服务端。这里先安装 nginx 然后再移除它,目的是利用这个过程吧 nginx 相关的依赖安装好并设定好系统环境。这个通过 apt 安装的 nginx 并不能直接使用,因为他并不包含我们需要的 RTMP 模块,所以将它移除。而后我们手工下载 nginx 和 nginx-rtmp-module 模块源码来手工编译安装,以获得我们最终需要的服务端。

sudo apt-get update

#安装 nginx

sudo apt-get -y<span> </span>install nginx

#移除 nginx

sudo apt-get -y remove nginx

sudo apt-get clean

#清空 nginx 的配置文件

sudo rm -rf<span> </span>/etc/nginx/*

#安装编译用的模块

sudo apt-get<span> </span>install -y curl build-essential libpcre3 libpcre3-dev libpcre++-dev zlib1g-dev libcurl4-openssl-dev libssl-dev

#创建存放网页的目录给 nginx 使用

sudo mkdir -p<span> </span>/var/www

#创建编译用的目录

mkdir -p ~/nginx_src

cd ~/nginx_src

#下载 nginx 源码包

wget http://nginx.org/download/nginx-1.11.8.tar.gz

#下载 nginx-rtmp-module 源码包

wget https://github.com/arut/nginx-rtmp-module/archive/master.zip

tar -zxvf nginx-1.11.8.tar.gz

unzip master.zip

cd nginx-1.11.8

#设定编译参数

./configure --prefix=/var/www --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-http_ssl_module --without-http_proxy_module --add-module=/home/pi/nginx_src/nginx-rtmp-module-master

#开始编译安装

make

sudo make install

比较漫长的等待之后,编译安装结束。这时可以测试 nginx 是否安装好。

nginx -v

正常的話,會顯示 nginx 的版本。

配置 nginx。

/etc/nginx/nginx.conf

在末尾添加如下配置:

rtmp {

    server {
        listen 1935;
        chunk_size 4096;
        application live {
            live on;
            record off;
        }<br>}

重启 nginx 服务。

sudo service nginx start

没有错误提示就表示成功了。
到这里 nginx 和 RTMP 模块都准备好了。

四、安装 avconv 和 GStreamer

安装的组件比较多,如果操作的时候因为软件源的问题总是出现错误难以完成,建议更换软件源试试。笔者用的是清华大学软件源安装的。

sudo nano/etc/apt/sources.list
deb https://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ stretch main contrib non-free rpi

deb-src https://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ stretch main contrib non-free rpi

开始安装

sudo apt-get update

sudo apt-get<span> </span>install libav-tools

#安装 GStreamer

sudo apt-get<span> </span>install gstreamer1.0-tools

#安装 GStreamer 扩展组件

sudo apt-get <span> </span>install libgstreamer1.0-0 libgstreamer1.0-0-dbg libgstreamer1.0-dev liborc-0.4-0 liborc-0.4-0-dbg liborc-0.4-dev liborc-0.4-doc gir1.2-gst-plugins-base-1.0 gir1.2-gstreamer-1.0 gstreamer1.0-alsa gstreamer1.0-doc gstreamer1.0-omx gstreamer1.0-plugins-bad gstreamer1.0-plugins-bad-dbg gstreamer1.0-plugins-bad-doc gstreamer1.0-plugins-base gstreamer1.0-plugins-base-apps gstreamer1.0-plugins-base-dbg gstreamer1.0-plugins-base-doc gstreamer1.0-plugins-good gstreamer1.0-plugins-good-dbg gstreamer1.0-plugins-good-doc gstreamer1.0-plugins-ugly gstreamer1.0-plugins-ugly-dbg gstreamer1.0-plugins-ugly-doc gstreamer1.0-pulseaudio gstreamer1.0-tools gstreamer1.0-x libgstreamer-plugins-bad1.0-0 libgstreamer-plugins-bad1.0-dev libgstreamer-plugins-base1.0-0 libgstreamer-plugins-base1.0-dev

这里安装了 avconv 和 GStreamer 两套视频采集组件。 avconv 的使用方式是:

avconv -f video4linux2 -r 24 -i<span> </span>/dev/video0 -f flv rtmp://localhost:1935/live

avconv 采用软编码实现,因此 CPU 消耗比较高,推荐用 GStreamer,GStreamer 的采集使用如下命令:

gst-launch-1.0 -v v4l2src device=/dev/video0 !<span> </span>'video/x-raw, width=1024, height=768, framerate=30/1' ! queue ! videoconvert ! omxh264enc ! h264parse ! flvmux ! rtmpsink location='rtmp://树莓派的IP地址/live live=1'

如果希望在后台运行这两个命令可以在命令后面添加&,例如:

gst-launch-1.0 -v v4l2src device=/dev/video0 !<span> </span>'video/x-raw, width=1024, height=768, framerate=30/1' ! queue ! videoconvert ! omxh264enc ! h264parse ! flvmux ! rtmpsink location='rtmp://树莓派的IP地址/live live=1' &

device=/dev/video0 这个参数可以省去,除非在有多个摄像头的时候,希望指定视频采集自某个指定的摄像头才需要这个参数。
采集的视频怎么播放呢?请看下面介绍。

五、实时视频的呈现

有多种方式呈现直播视频画面:
1、使用 RTMP 播放器播放视频流
例如 VLC 等播放器(桌面版和手机版均有)支持 RTMP 视频流播放,填入 rtmp://树莓派的IP地址/live即可播放。不过这个软件有数十秒的缓冲延迟,需要设定缓冲时间来缩短延迟。

2、使用 Strobe Media Playback 创建播放页面,通过网页播放视频流
这个是在树莓派上创建一个带有播放功能的网页,播放器选用 Strobe Media Playback,当然你也可以选择其他支持 RTMP 的播放器控件。播放的时候用浏览器打开 http://树莓派的IP地址/index.html 进入播放界面。下面介绍这个播放页面的创建方法。

mkdir -p ~/strobe_src
cd ~/strobe_src
wget http://downloads.sourceforge.net/project/smp.adobe/Strobe%20Media%20Playback%201.6%20Release%20%28source%20and%20binaries%29/StrobeMediaPlayback_1.6.328-full.zip
unzip StrobeMediaPlayback_1.6.328-full.zip
sudo cp -rfor\ Flash\ Player\ 10.1/var/www/html/strobe
sudo nano/var/www/html/index.html

填入如下内容,记得把下面的“树莓派的IP地址”替换成你的树莓派实际的IP地址。IP地址可以通过 ifconfig 命令查看。

<!DOCTYPE html><br><br><html><br><br><head><br><br><title>Live Streaming</title><br><br><!-- strobe --><br><br><script type="text/javascript" src="strobe/lib/swfobject.js"></script><br><br><script type="text/javascript"><br><br>  var parameters = { <br><br>     src: "rtmp://{pi_address}/rtmp/live"<span class="s1">,</span> <br><br>     autoPlay: false<span class="s1">,</span> <br><br>     controlBarAutoHide: false<span class="s1">,</span> <br><br>     playButtonOverlay: true<span class="s1">,</span> <br><br>     showVideoInfoOverlayOnStartUp: true<span class="s1">,</span> <br><br>     optimizeBuffering : false<span class="s1">,</span> <br><br>     initialBufferTime : 0.1<span class="s1">,</span> <br><br>     expandedBufferTime : 0.1<span class="s1">,</span> <br><br>     minContinuousPlayback : 0.1<span class="s1">,</span> <br><br>     poster: "images/poster.png" <br><br>  }<span class="s1">;</span> <br><br>  swfobject.embedSWF<span class="s1">(</span><br><br>    "strobe/StrobeMediaPlayback.swf"<br><br>    <span class="s1">,</span> "StrobeMediaPlayback"<br><br>    <span class="s1">,</span> 1024<br><br>    <span class="s1">,</span> 768<br><br>    <span class="s1">,</span> "10.1.0"<br><br>    <span class="s1">,</span> "strobe/expressInstall.swf"<br><br>    <span class="s1">,</span> parameters<br><br>    <span class="s1">,</span> {<br><br>      allowFullScreen: "true"<br><br>    }<br><br>    <span class="s1">,</span> {<br><br>      name: "StrobeMediaPlayback"<br><br>    }<br><br>  <span class="s1">);</span><br><br></script><br><br></head><br><br><body><br><br><div id="StrobeMediaPlayback"></div><br><br></body><br><br></html>

播放的时候用浏览器打开 http://树莓派的IP地址/index.html 进入播放界面。

3、推送至斗鱼直播平台观看
你可能注意到了 GStreamer 这个命令中有 location 这个参数。这个参数是设定采集到的视频流推向哪里,通过设定这个参数可以将视频流推向任何支持 RTMP 协议的服务器。

gst-launch-1.0 -v v4l2src device=/dev/video0 !'video/x-raw, width=1024, height=768, framerate=30/1' ! queue ! videoconvert ! omxh264enc ! h264parse ! flvmux ! rtmpsink location='rtmp://树莓派的IP地址/live live=1'

斗鱼平台同样采用了 RTMP 协议传输直播视频,以斗鱼平台为例来说明一下推流到斗鱼的方法。

首先获取斗鱼的 RTMP 推流地址。开启了直播室之后可以获得推流码。注意,斗鱼的推流码是有时限的,取到推流码需要尽快使用以免过期。

把这两个参数组合起来(中间加上/)。修改之后的命令例如:

gst-launch-1.0 -v v4l2src device=/dev/video0 !'video/x-raw, width=1024, height=768, framerate=30/1' ! queue ! videoconvert ! omxh264enc ! h264parse ! flvmux ! rtmpsink location='rtmp://send1.douyu.com/live/1372rSOMdcBJ8UHD?wsSecret=96d2k4ecdf267d17b8e8c38b6a4a6efd&wsTime=59f92e2e&wsSeek=off live=1'

然后就可以开播了。

打个小广告,欢迎大家关注我的斗鱼直播间~
https://www.douyu.com/1372
这里不定期直播宠物鱼。
应用以上技术实现的远程喂鱼项目:
http://maker.quwj.com/program/nature-aquarium

总体上三种播放方式都有一定延迟,其中网页 Strobe Media Playback 播放延迟最小,大概在1秒左右。VLC 延迟比较固定默认约20秒,个别平台的版本是可以设置延迟数值的笔者没有亲力尝试。然后是斗鱼平台,斗鱼随着播放时间变长延迟也越来越长,需要刷新直播间页面才会同步。

搭建过程有问题请在树莓派实验室原文下面留言,转载请保证文章内容完整、注明出处并附带原文链接~

本文来自:http://shumeipai.nxez.com/2017/11/01/build-rtmp-stream-live-server-with-raspberry-pi.html

自行移植树莓派64位内核系统的方法介绍

不久前我们推荐了 chainsx 的《树莓派 Ubuntu 64位系统玩家体验版》。作者进一步提供了自行编译上述系统并制作镜像文件的方法,分别介绍了如何通过交叉编译和在树莓派上直接编译,授人以渔啦~

你可以通过ubuntu16.04交叉编译,也可以直接在树莓派上编译。
我们遵循树莓派官方的内核编译引导
这里,感谢bamarni的思路提供。

在电脑上交叉编译

构建内核
你需要一个Ubuntu16.04的64位版本。
安装交叉编译环境

apt-get update
apt-get install -y bc build-essential gcc-aarch64-linux-gnu git unzip

获取源码

gitclone–depth=1-b rpi-4.8.y https://github.com/raspberrypi/linux.git

接下来,开始你的构建,分别运行以下命令:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcmrpi3_defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-

这时,你可以去泡杯茶,看看电视,或者吃鸡。。。。
因为这要一点时间。
准备一个系统
这里,我拿raspbian做例子(有些数字你要自己改,不要太死板)。
先从官网下载raspbian(建议下载lite)。
解压后得到img文件。
然后,我们用下面的命令审查:

fdisk- l raspbian-jessie-lite.img
Diskraspbian-jessie-lite.img:1.3GiB,1390411776 bytes,2715648 sectors
Units: sectors of 1*512=512 bytes
Sectorsize(logical/physical):512 bytes /512 bytes
I/O size(minimum/optimal):512 bytes /512 bytes
Disklabel type: dos
Disk identifier:0x244b8248
DeviceBootStartEndSectorsSizeIdType
raspbian-jessie-lite.img1 8192 137215 129024 63M c W95 FAT32 (LBA)
raspbian-jessie-lite.img2 137216 2715647 2578432 1.2G83Linux

注意,上面两条很关键!

我们可以在我们的文件系统上挂载这些分区(当然,你也可以直接写入sd卡),从根分区开始:

mount-o loop,offset=70254592 raspbian-jessie-lite.img /mnt

offset 取决于扇区大小(512):70254592 = 512 * 137216
接着是启动分区:

mount-o loop,offset=4194304,sizelimit=66060288 raspbian-jessie-lite.img /mnt/boot

offset :4194304 = 512 8192,sizelimit:66060288 = 512 129024
安装内核
执行以下命令,将编译好的内核以及设备树复制到系统中(前提是你编译完了):

cp arch/arm64/boot/Image/mnt/boot/ kernel8.img
cp arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dtb /mnt/boot/

执行以下命令,安装内核模块。

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu INSTALL_MOD_PATH=/mnt modules_install

执行以下命令,调整config.txt。

echo kernel=kernel8.img >> /mnt/boot/config.txt

不过,保险起见,你还是手动修改,如果没有的话,加上kernel=kernel8.img,有的话,修改为kernel=kernel8.img
卸载分区

umount /mnt/boot && umount /boot

大功告成!

在树莓派上编译

其实差不多。就是不用交叉编译工具罢了,不过,时间有点久。
注意,要使用aarch64(arm64)的系统进行编译!
不过,这里有现成的Debian | Ubuntu(如果你用Ubuntu的话,请将源换成中科院的mirrors.opencas.org)。
安装依赖

apt-get update
apt-get install -y bc build-essential

获取源码包

git clone https://github.com/raspberrypi/linux.git

开始编译

make ARCH=arm64 bcmrpi3_defconfig
make ARCH=arm64

这时,考验你心态的时候到了,可能要一个多小时吧!
如果你想多核编译,使用-j4参数。
准备一个要移植的系统。
这里,给几个推荐。
ubuntu 15.10   |   CentOS
下载下来后,按照上面方法挂载,或直接写入sd卡。
安装内核
执行以下命令,将编译好的内核以及设备树复制到系统中(前提是你编译完了)

cp arch/arm64/boot/Image/mnt/boot/ kernel8.img
cp arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dtb /mnt/boot/

执行以下命令,安装内核模块:

make ARCH=arm64 INSTALL_MOD_PATH=/mnt modules_install

执行以下命令,调整config.txt。

echo kernel=kernel8.img >> /mnt/boot/config.txt

不过,保险起见,你还是手动修改,如果没有的话,加上kernel=kernel8.img,有的话,修改为kernel=kernel8.img

卸载分区

umount /mnt/boot && umount /mnt

至此,大功告成

制作一个自己的系统

这里,简要说一下制作根分区(rootfs)的思路。
如果你熟悉 debootstrap,用它构建你自己的(这回比较棘手,因为它需要一些手工调整,它最初的目的是在已经运行的主机上进行 chroot,而不是为其他机器构建根文件系统)。
我建议使用 multistrap,这里有一个很好的教程:http://free-electrons.com/blog/embdebian-with-multistrap/

同样,提供几个根分区的压缩文件。
Ubuntu 17.04   |   CentOS

小贴士:对于第一次使用树莓派 64位 Ubuntu 的用户,建议将 Ubuntu15.10 的源换成中科院的源 mirrors.opencas.org 不然的话将无法使用哦。
项目 GitHub:https://github.com/chainsx/ubuntu64-rpi
Maker 趣无尽项目主页:http://maker.quwj.com/project/28

本文来自:树莓派实验室

树莓派上使用 GitLab 搭建专业 Git 服务

GitLab是一个专业的Git解决方案,功能强大,和GitHub类似,而且其Community Edition (CE)是免费的,完全可以胜任为中小团队提供专业代码托管服务的工作,当然更重要的是它可以在Raspberry Pi上部署运行。

准备

项目首页:https://about.gitlab.com
下载页:https://packages.gitlab.com/gitlab/raspberry-pi2
下载地址(打开页面,点击右上角的Download按钮):
https://packages.gitlab.com/gitlab/raspberry-pi2/packages/debian/jessie/gitlab-ce_8.13.0-ce.0_armhf.deb
下载得到gitlab-ce_8.13.0-ce.0_armhf.deb文件。
注意版本要选择jessie,也就是Debian 8,因为现在的Raspbian是基于它打造的。

官网给出了在线安装的方法,但是我试了几次,可能由于国内到GitLab下载服务器之间的网络状况不好,很难在线安装成功。
国内的软件源即使有GitLab的镜像,通常也没有支持Raspberry Pi架构的分支。

所以这里给出先下载安装包,然后离线安装到Raspberry Pi上的方法。

开始安装

先安装一些必要的依赖包:

sudo apt-get install curl openssh-server ca-certificates postfix apt-transport-https

安装postfix时,会弹出一些设置,这是和发邮件相关的,如果不需要邮件功能,这里的设置并不重要。

 

等待上述依赖包安装完成后,把之前下载的安装包gitlab-ce_8.13.0-ce.0_armhf.deb上传到Raspberry Pi的文件系统里。
正式安装deb包

sudo dpkg -i gitlab-ce_8.13.0-ce.0_armhf.deb

这个包有281MB,包含123034个文件,因此安装会有些慢,卡在下面这步是正常的,耐心等待一下。

安装完成提示信息:

根据提示,需要运行:

sudo gitlab-ctl reconfigure

看到如下提示就配置完成了

初始设置

管理员用户是root
首次登录后会要求修改密码(8位及以上)

在浏览器访问Raspberry Pi的IP,会跳转到设定密码的页面。

设定完成后,用新密码登录root用户。

这是管理员用户,只用它来添加普通用户,在普通用户里新建仓库来托管代码。
点击界面右上角的小扳手图标,进入Admin Area,这是管理员独有的区域。
在user里新建一个普通用户。

注意初始的Projects limit只有10,只能创建10个projects。如果觉得不够用,可以放宽一点限制。

普通用户的密码会发送到邮箱,如果之前邮箱没配置好,可能会收不到,或者如果是内网使用,邮件也无法发出。这个问题可以这样解决:

管理员里可以用管理权限修改这个用户的密码,改完后告诉该用户这个密码,该用户在首次登录后,会被提示设置一个新密码。
如果以后使用时该用户忘记了密码,管理员也可以登录Admin Area重置。
这样就不需要邮件来重置密码,缺点是需要管理员介入,对于中小团队这样的管理方法是可取的(可以由项目组织者充当管理员)。
另外在Admin Area界面右侧有个齿轮形状的图标,点击这里可以修改一些全局设定(包括前面初始的Projects limit等), 根据提示修改就行了。

修改服务端口

默认使用80端口,如果需要修改,可以修改/etc/gitlab/gitlab.rb中如下图的2处地方,比如这样就修改成了7000端口。

两个地方都要修改。
注意保存文件后,要运行如下命令使得配置生效:

sudo gitlab-ctl reconfigure

可以看到能使用7000端口访问了,Project path也是正确的。

一些实用的维护命令

#修改任何配置文件后都要输入如下命令使配置生效。
sudo gitlab-ctl reconfigure
 
#页面缓存清除:
sudo gitlab-rake cache:clear RAILS_ENV=production
 
#GitLab各组件启动:
sudo gitlab-ctl start
 
#GitLab各组件停止:
sudo gitlab-ctl stop
 
#GitLab各组件重启:
sudo gitlab-ctl restart
 
#禁用GitLab开机自启动:
sudo systemctl disable gitlab-runsvdir
 
#启用GitLab开机自启动:
sudo systemctl enable gitlab-runsvdir

本文来自:

树莓派上使用 GitLab 搭建专业 Git 服务

基于Zero W和Batocera的游戏掌机

使用batocera系统配置树莓派Zero W掌机,batocera系统与其他游戏机系统相比性能要求低,非常适合用于Zero这种低配置的板子上使用。

下载镜像

这个网站,选择针对树莓派Zero W的镜像下载,Windows用Win32DIskImager直接烧写,Linux用dd命令即可。
 

初次配置

通过HDMI线连接电视机或者显示器,给树莓派正常供电,系统会自动分配空间,自动配置完,然后强制关机直接切断电源就行。

配置分辨率

考虑到我们需要用小屏幕来作为掌机的显示,系统不会默认就直接适配屏幕,以我的这个5寸屏幕为例

需要修改一些配置文件,这个步骤需要Linux系统或者虚拟机。
首先需要修改/RECALBOX目录下的config.txt
将下面这段加到里面去(可能需要sudo命令行)。
framebuffer_width=800
framebuffer_height=480
hdmi_force_hotplug=1
hdmi_group=2
hdmi_mode=87
hdmi_cvt  800  480  60  6  0  0  0
device_tree=bcm2710-rpi-3-b.dtb
dtparam=spi=on
把/SHARE/system/recalbox.conf中的两处CEA 4 HDMI改成DMT 87 HDMI
使用其他屏幕的时候用类似的操作就行了,配置成功之后应该可以使batocera的主屏幕和游戏界面都完全适配使用的硬件屏幕。

设置GPIO控制

修改/SHARE/system/recalbox.conf中的两行配置
controllers.gpio.enabled=1  
controllers.gpio.args=map=1,2 => controllers.gpio.args=map=1
重启之后就可以尝试用上面这张图的相关引脚了,默认是上拉的引脚,所以只要把引脚比如27号连一下GND,看他会不会有左滑的效果,如果有效果的话,就是说软件上配置成功了,硬件上还需要做一些事情,需要焊一块小型的掌机来操作才行。
 
总体思路就是在一块洞洞板上焊接需要数量的微动开关,然后每个开关一边连到相应的开关,另一边一起连到GND即可,具体随意就行,包括整个的布局之类的,只要按下去有效果就行了。
比如像我这样的很多飞线的,能用就行…
使用游戏机

正式玩游戏之前需要一些其他额外的配置
配置WI-FI

游戏上传在无法联网的板子上,我们只能通过直接对SD卡读写,拔下SD卡然后往里面复制粘贴进去游戏ROM文件,需要用Linux系统或者虚拟机来打开SD卡,ROM放置的目录在/recalbox/share/roms,里面有分开各种模拟器的目录,把相应的游戏rom或者压缩包粘贴到相应的模拟器目录下就好了。

网络上传对于能联网的板子,尤其是树莓派3和ZERO w这类有无线WiFi的板子,完全可以通过网络的方式上传游戏文件,而不需要麻烦的插拔SD卡。

首先肯定需要联网,可以看上一篇文章中的联网的步骤,确保板子和PC在同一局域网里面

打开我的电脑中的网络,应该能看到RECALBOX的一个网络位置

进入这个位置,就能看到下面的目录结构

直接复制相应的ROM文件到对应的模拟器目录下面,然后在游戏机上,进入主菜单的游戏设置,然后选择更新游戏列表,之后再进入对应的模拟器目录,就能看到刚刚复制进去的游戏了。

有时候可能在网络中直接看不到这个网络位置,我们也能在我的电脑的地址栏里面,直接输入\\RECALBOX或者对用的ip地址,比如\\192.168.3.18,应该也能进入上面的那个目录结构,然后做类似的操作即可。

最后就能用自己做的手柄开始玩各种复古游戏了,只要你能找到它的ROM。

树莓派 Ubuntu 64 位系统玩家体验版

 

前言

我对于 Linux 里的 Ubuntu 情有独钟,包括对树莓派3也不放过,树莓派3有一个64位的CPU,但一直使用的是32位的系统,太憋屈了,最近看见 barnami 大神移植了 Debian stretch arm64 到树莓派上(项目地址 https://github.com/bamarni/pi64),不过,我想说的,还是 Ubuntu。
Ubuntu 的 arm64 版本可不好找,不像 Debian 有一个健壮的 arm64 移植版,所以我找了很久,找到了一个15.10(没办法,只能这样了),对于 15.10 官方不给支持了(毕竟不是LTS)。

介绍

本系统由以下组成

  • boot: 原汁原味官方 Ubuntu 16.04 armhf for Raspiberry Pi 3
  • firmware: 由树莓派官方的 linux-rpi-4.9.y 编译的 aarch64
  • rootfs: Ubuntu15.10 (无力吐槽)

对于这次移植呢,有点小问题,就是开机在boot界面时会连接某服务器,但这服务器访问不了,会重试几次,但还不善罢甘休,请求 192.168.1.1 的相应地址(废话,更不行了),导致开机可能要花一点时间,不过不影响系统的正常使用,各项功能没有太大问题。

欢迎大家参与测试,优化,调试。

特点

  • 使用了 aarch64 内核,完美搭建arm64系统底层
  • 使用了 arm64 系统,性能更好
  • 完美释放出了树莓派3的性能
  • 驱动各方面迄今无太大问题
  • 稳定性有待提高

暂时没有升级到 16.04 或 17.04,可以借助官方帮助文档进行交叉升级。

传送门

Ubuntu 15.10 arm64
GitHub 地址: https://github.com/chainsx/ubuntu64-rpi
版本说明:
默认用户:ubuntu 密码:ubuntu;root 用户密码:root
默认开启 SSH,不想要的自己去关。
默认为命令行,想要图形界面的自己装。
第一次开机时不会拓展 rootfs 分区,意思是你需要自己拓展,用 fdisk 或 gparted 来拓展吧。

Ubuntu 17.04 for rpi3(64位内核,32位系统)
GitHub 地址: https://github.com/chainsx/ubuntu-17.04-for-RaspberryPi3
版本说明:
集成了raspi-config,你只需要在命令行里输入raspi-config就行了。
默认用户名:ubuntu 密码:chainsx007
支持安装gnome, apt install gnome 即可,unity 待测(不过,gnome卡出翔)。
默认为命令行,需要桌面的自行安装,推荐lxqt,:安装apt install lxqt。
因为是源自 rpi2 移植的,所以在 boot 分区有两个内核,一个是rpi3的(默认),另外一个是rpi2的(当然不支持64位内核),需要在config.txt里将kernel=kernel8.img改为kernel=uboot.bin。我觉得,你要在pi2上用的话还不如直接在官方下载。

关于我

本人喜欢玩 Linux,更多的是喜欢乐在其中,结交更多好友,学习更多技术。
小编按:本文作者 Github 中提供了联系方式 1396219808[a]qq.com,如有项目相关问题可尝试联系原作者。

虽然只是推荐,但我相信,树莓派3的64位除了 openSUSE 的系统(Debian、Ubuntu)是非常惊人的吧!
我也亲自测试过,这两种系统完全完全的把树莓派3的64位性能给释放出来了,十分惊人,不推荐一下完全对不起原作者的苦心和树莓派的 ARMv8 芯片。
原作者表示:原文无任何版权,我们只是乐在其中,以后还要定期更新,我其实想抽空一直维护这个系统,直到Ubuntu官方的系统正式发布为止。此系统无任何风险(因为我以前制作安卓第三方ROM时就被质疑过,但最后证明了的却无任何风险,这个也一样)。

作者:CX_Dandelion

本文来自

http://shumeipai.nxez.com/2017/09/10/raspberry-pi-ubuntu-64-bit-system-player-experience-version.html

 

 

树莓派安装运行 Minecraft 1.8.9 教程

本文来自 Gloomy Ghost 的投稿,介绍了如何在树莓派2B上安装运行 Minecraft 1.8.9。

更新系统

sudo apt-get update && sudo apt-get -y upgrade

安装相应的显示程序

sudo apt-get -y install xcompmgr libgl1-mesa-dri && sudo apt-get -y install libalut0 libalut-dev && sudo apt-get -y install mesa-utils

配置显卡显示选项

sudo raspi-config

找到Advanced Options,设置GL Driver为GL (Full KMS)。

超频
这个不用我教了吧,超到 High(1000MHz)就行了。

然后重启。

sudo reboot

测试显卡是否配置完成

glxgears

一、使用官方账号游戏

获取官方启动器

mkdir ~/Minecraft; mkdir ~/Minecraft/Natives; cd ~/Minecraft && wget http://ouav818sk.bkt.clouddn.com/raspimc/Minecraft.jar

这里我创建2个文件夹,用于存放文件,运行mc启动器,下载游戏文件。

java -jar Minecraft.jar

下载配置文件

登陆

新建配置

版本选择1.8.9

下载安装

 

二、无账号游戏

下载 Hello Minecraft!! Launcher

mkdir ~/Minecraft; mkdir ~/Minecraft/Natives; cd ~/Minecraft && wget https://github.com/huanghongxun/HMCL/releases/download/v2.5.3/HMCL-2.5.3.88.jar

这里我创建2个文件夹,用于存放文件,运行mc启动器,下载游戏文件。

java -jar HMCL-2.5.3.88.jar

下载运行库文件

cd ~/Minecraft/Natives && wget http://ouav818sk.bkt.clouddn.com/raspimc/liblwjgl.so && wget http://ouav818sk.bkt.clouddn.com/raspimc/libopenal.so

更新lwjgl

cd ~/.minecraft/libraries/org/lwjgl/lwjgl/lwjgl/2.9.4-nightly-20150209 && rm lwjgl-2.9.4-nightly-20150209.jar; wget http://ouav818sk.bkt.clouddn.com/raspimc/lwjgl-2.9.4-nightly-20150209.jar

(基于Roger Allen的教程:http://rogerallen.github.io/jetson/2014/07/31/minecraft-on-jetson-tk1/
复制运行脚本)

cd ~/Minecraft/ && wget http://ouav818sk.bkt.clouddn.com/raspimc/run.sh && sudo chmod +x run.sh

编辑 run.sh(正版)
编辑下面的配置,填上你的游戏账户信息。
MINECRAFT_LOGIN
MINECRAFT_USERNAME
MINECRAFT_PASSWORD
完成正版登陆

运行游戏

./run.sh

 

相关代码如果觉得不方便,可以到这里查看,我把所有命令整合了一下。

 

转载自树莓派实验室