用树莓派和宜家台灯玩转AR投影黑科技

MAKER:Nord Projects/译:趣无尽 Cherry(转载请注明出处)
这是一款用树莓派(Raspberry Pi)和宜家台灯制作的智能家具,应用 Android Things 系统来实现 AR(增强现实)投影灯。
Nord Projects 表示我们已经制作了一些类似的 AR 智能家具的项目,如:投影给时钟显示约会标记、投影给扬声器显示当前正在播放的歌曲。
在不久的未来,将使用投影来呈现环境信息,以及日常物体中的相关用户界面。与屏幕不同,当台灯的投影不再需要时,它们就会慢慢消失。
这是一个非常明晰的教程,用照片和GIF很好地加以说明。这个项目不需要大量的实践经验,你只需要3D打印出所有组件,将所有的东西组合在一起即可,因为一切都是开源的,感兴趣的趣友们动手试试看吧:)

项目将使用宜家的灯具、激光投影仪和Android things创建一个互联的投影仪。通过配套的应用程序设置迷你的应用程序,在线连接数据反馈并显示预计的用户界面。
改造的核心是Android Things,一款来自Google的新操作系统,专为嵌入式设备和物联网而设计。 Android Things更容易实现软件与设备的连接,尤其是对于已经熟悉Android的移动开发人员!

台灯投影仪使用宜家的Tertial灯现成部件,3D打印附件和我们的开源软件。
如果你以前没有使用过Android的东西也不必担心。 我们将引导你完成这一过程,以便立即启动并运行这个项目。

所需材料

  • 宜家 Tertial 台灯 x1
  • 10mm x 2m编织电缆护套x1
  • 电缆扎带x4
  • M2 x 4mm自攻螺丝钉x6
  • M2.2 x 8mm自攻螺丝钉x3
  • M3 x 20mm自攻螺丝钉x5
  • M48mm翼形螺丝钉x2
  • M410mm螺丝钉x2
  • UO智能光束投影仪x1
  • Raspberry Pi 3 B型x1
  • Raspberry Pi V2相机(可选)x1
  • ADXL345加速传感器x1
  • 母对母跳线(75mm)x4
  • MicroSD卡(大于2GB)x1
  • 直角microHDMI转HDMI高清线 x1
  • 直角(下弯)microUSB延长线x2
  • Micro-USB电源线 6英尺(约183mm)x2
  • 双端口USB电源适配器x1

所需工具

  • 螺丝刀(十字头,型号PH1,PH0)
  • Rasp文件(+副选项)
  • 量角器或数码角度标尺 x1
  • 磨砂纸(80砂砾) x1
  • 烙铁+焊料(刀头可选)
  • 剪切工具(用于切割灯丝,电缆扎带) x1
  • 内六角扳手4(用于灯头平头螺丝+插入尺寸4) x1
  • 类似锥子或螺丝刀这样可以取下灯泡罩的小尖头物品 x1

步骤1:台灯内部的准备工作

1、将电源线从灯中取出
松开灯架侧面的螺丝,然后切断灯头附近的电源线,通过金属手臂将电源线拉出。
2、拆下灯泡附件
使用六角扳手,卸下固定电缆的螺丝。在灯头的侧面插入一把小螺丝刀。 轻轻撬起塑料卡舌以松开插座。 (把它弄松可能有点棘手。)将灯头转过来并取下固定插座的塑料螺丝。 你现在可以取下灯泡附件了。
3、修改灯臂
从手臂上拧下灯头,然后取下塑料夹。将手臂接口的直角磨成到半圆形。
4、夹住灯头
从手臂上拧下灯头。 从金属延伸件上取下所有部件。将金属夹的边缘磨平,使它们均匀平滑。
5、处理塑料垫片
取出从金属附件的塑料垫片。 使用砂纸将其两端磨成约4.5mm厚。处理后的塑料片可以更好地固定金属部件,防止头部随着长时间的使用而滑落。
6、拧紧螺丝
拧紧灯上的所有螺丝钉,使它可以很好地移动。

步骤2:3D打印附件

1、测量灯的角度
每个灯都会不同,所以需要调整CAD模型。 使用量角器或数码角度尺,测量凹槽和灯臂之间的角度。
2、获取CAD
在OnShape中打开CAD模型(开源项目免费使用)。 这是一份公开文件,所以请复印一份供你调整。
3、调整CAD
点击标题为’EDIT THIS – arm pilot holes’的草图。选择上面标有显示的测量值并将数值更改为步骤1中测量的角度。输入后将相应的旋转相关特征。
4、导出你的模型
三个部分中的每一个,右键单击附件名称并导出。 使用以下设置:
格式:STL

  • STL格式:二进制
  • 单位:毫米
  • 分辨率:良好
  • 选项:下载

5、3D打印

使用3D打印机打印文件。我们使用了Ultimaker 2+,但你可以随意使用任何型号的3D打印机。
我们的Ultimaker 2+设置:

  • 材料:PLA
  • 喷嘴:0.4毫米

使用默认设置,微调:

  • 增加10mm的边缘
  • 第一层的喷嘴温度为200°C
  • 剩下部分的喷嘴温度为210°C
  • 打印顶部部件(顶盖和手臂)时,壁厚度设置为3毫米。

步骤3:组装硬件

1、焊接加速度传感器
将一行的9个针头引脚焊接到加速传感器上。确保它们延伸出电路板的正面。
2、嵌入投影机
将投影机按入底座;使它安置妥当。将微型HDMI电缆插入投影机。
3、组装手臂和盖子
使用2 x 20毫米M3螺丝钉将3D打印的手臂连接到配套的盖子上。小心地将手臂的底座与盖子上的定位器对齐。
4、螺纹固定插件
使用六角扳手,将10mm M4螺纹插件拧入臂顶部的两个孔中,直至它们与表面齐平。
5、连接跳线
使用跳线将加速度传感器与Raspberry Pi上的I2C总线连接。务必慢慢来,确保这两个组件安装到的正确引脚上!
6、安装相机(可选)
提起相机连接器上的夹子并插入带状电缆。将夹子向下推,将其固定到位。将相机安装到位。
7、连接树莓派
将Raspberry Pi移动到位并用3个8mm M2.2螺丝固定。
8、连接加速度传感器
使用2个M24毫米螺丝将加速传感器连接到底座。
9、连接盖子和手臂
使用3个20毫米M3螺丝将盖子和手臂连接到底座。
10、HDMI高清线
将HDMI高清线插入Raspberry Pi。

步骤4:接线

1、切割护套
将编织电缆护套切成166CM长。我们建议在烙铁上使用刀具附件以防止电缆护套散开。
2、穿线套
将两根USB电缆穿过编织电缆护套。
3、将电缆传入灯罩内
将Micro-USB电缆的两端插入灯头后部。
4、直角连接器
将电缆穿过3D印刷臂的侧面。 连接直角Micro-USB延长线。 插入USB电源适配器。

步骤5:设置软件

1、 获取Android Things
准备好你的microSD卡,并按照以下步骤操作https://developer.android.com/things/hardware/raspberrypi.html#flashing_the_image 刷新SD卡上的Android Things。
2、启动Android Things
将microSD插入Pi并连接USB电源。
3、设置WiFi
运行“android-things-setup-utility”。出现提示时,选择“2 – 在现有Android Things设备上设置Wifi”,然后选择“1 – Raspberry Pi 3”。接下来,通过网络将Raspberry Pi连接到你的计算机(或路由器),然后按“Enter”键。按照屏幕提示设置WiFi。现在你可以拔掉Raspberry Pi。
4、安装并运行代码

从GitHub下载代码并在Android Studio中打开它。一旦Gradle同步,打开一个终端窗口并输入:
adb连接android.local
然后选择‘things’设置按绿色键为上传并运行代码。
如果获取错误?请查看我们的故障排除指南。

5、给投影机供电
将Micro-USB插入投影机并打开电源。检查显示器,如果以错误的屏幕分辨率启动,灯会自动重启,因此你可能需要等待完成。当你看到启动画面时,你完成了,太棒了!
如遇到问题?请查看我们的故障排除指南

步骤6:组合在一起

1、连接硬件
将组装好的硬件插入灯头。务必检查摄像头和投影机是否垂直对齐。
2、拇指固定螺钉
一旦排好后,用手指固定螺丝。
3、电缆扎带
用小电缆扎带将电缆固定到位。在灯头附近留出足够的余量以便将硬件装入和取出。

步骤7:下一步会是什么?

在手机上安装相应的应用程序(使用Android Studio)并使它与台灯连接。
向下、向前或向上移动台灯,投影画面在默认通道之间切换。
通过点击手机页面上的方向选择来改变频道。
最后下一步
定制你的专属台灯 – 混合搭配宜家灯具部件或喷涂你自己的灯具。按照本指南制作自己的频道。以下是我们想到的一些事情:

  • 桌面上下载你喜欢的新闻软件APP,或者你的WeChat
  • 一个用来逗猫的光点
  • 使用网络摄像头和计算机摄像头用作你的台灯的相机投影系统
  • 尝试处理Android Things

故障排除指南

adb connect android.local返回错误
可能是你的网络无法解析该名称,或者您的设备未连接到WiFi。 打开投影机并查看Android Things Launcher – 它会告诉你本地网络上的IP地址。
如果列出了IP地址,请在终端中输入adb connect <your-device-ip>
如果这不起作用,或者你的设备没有IP地址,那么你的WiFi网络可能不支持此类设备。 尝试再次配置WiFi,如果可能的话,连接到不同的网络。

源代码

所有源码均可在 GitHub 下载,包括用于 Android Things 的源码、运行投影仪和 Android Mobile 相关 APP 源码。
GitHub:https://github.com/nordprojects/lantern
项目主页:http://nordprojects.co/lantern
MAKER 趣无尽页面:http://maker.quwj.com/project/54

Kano Computer Kit Touch让孩子打造属于自己的平板电脑

据外媒报道,有些人可能会说平板电脑已经死了,但iPad、Surafce Goe以及变形本则给出了另外一个答案。现在,触屏已经成为大部分孩子跟智能手机还有平板电脑互动的首个模式。所以如果打算教他们如何打造他们的电脑或许可以先教叫他们如何打造一台平板。这正是Kano DIY套件想要带来的。

这款名为Computer Kit Touch的电脑套件基本以触屏为中心,其是Kano公司另外一款产品–Computer Kit Complete的升级,孩子们可以用它打造自己的树莓派平板。

 

不过真要严格说起来,它不像iPad,虽然它拥有类似于平板电脑的功能。毕竟它是由一台树莓派和简单的硬件打造。套件打造的意义则在于通过提供色彩鲜艳的部件和配有插图的说明让孩子以一种有趣的方式打造自己的电脑。在组装完成,Kano电脑就会通过一些编程工具和游戏为孩子们打开一个全新、有趣的学习世界。

据悉,Kano Computer Kit Touch售价249.99美元,另外Kano还提供了一些额外的插件,诸如30美元的运动传感器、80美元的RGB LED阵列以及即将推出的扬声器和受哈利波特启发的编程棒。

 

 

 

使用树莓派构建一个婴儿监视器

香港很湿热,即便是晚上,许多人为了更舒适,在家里也使用空调。当我的大儿子还是一个小婴儿的时候,他卧室的空调还是需要手动控制的,没有温度自动调节的功能。它的控制器只有开或者关,让空调整个晚上持续运行会导致房间过冷,并且也浪费能源和钱。

我决定使用一个基于树莓派的物联网解决方案去修复这个问题。后来我进一步为它添加了一个婴儿监视器插件。在这篇文章中,我将解释我是如何做的,它的代码在 我的 GitHub 页面上。

设计空调控制器

解决我的问题的第一个部分是使用了一个 Orvibo S20 可通过 WiFi 连接的智能插头和智能手机应用程序。虽然这样可以让我通过远程来控制空调,但是它还是手动处理的,而我希望尝试让它自动化。我在 Instructables 上找到了一个满足我的需求的项目:他使用树莓派从一个AM2302 传感器上测量附近的温度和湿度,并将它们记录到一个 MySQL 数据库中。

使用压接头将温度/湿度传感器连接到树莓派的相应 GPIO 针脚上。幸运的是,AM2302 传感器有一个用于读取的 开源软件,并且同时提供了 Python 示例。

与我的项目放在一起的用于 AM2302 传感器 接口的软件已经更新了,并且我使用的原始代码现在应该已经过时了,停止维护了。这个代码是由一个小的二进制组成,用于连接到传感器以及解释读取并返回正确值的 Python 脚本。

将传感器连接到树莓派,这些 Python 代码能够正确地返回温度和湿度读数。将 Python 连接到 MySQL 数据库很简单,并且也有大量的使用 python-mysql 绑定的代码示例。因为我需要持续地监视温度和湿度,所以我写软件来实现这些。

事实上,最终我用了两个解决方案,一是作为一个持续运行的进程,周期性(一般是间隔一分钟)地获取传感器数据,另一种是让 Python 脚本运行一次然后退出。我决定使用第二种方法,并使用 cron 去每分钟调用一次这个脚本。之所以选择这种方法的主要原因是,(通过循环实现的)持续的脚本偶尔会不返回读数,这将导致尝试读取传感器的进程出现堆积,最终可能会导致系统挂起而缺乏可用资源。

我也找到了可以用程序来控制我的智能插头的一个 Perl 脚本。它是解决这种问题所需的一部分,因此当某些温度/湿度达到触发条件,将触发这个 Perl 脚本。在做了一些测试之后,我决定去设计一个独立的 checking 脚本,从 MySQL 去拉取最新的数据,然后根据返回的值去设置智能开关为开或关。将插头控制逻辑与传感器读取脚本分开,意味着它们是各自独立运行的,就算是传感器读取脚本写的有问题也没事。

配置一个打开/关闭空调的温度值是很有意义的,因此,我将这些值转移到控制脚本读取的配置文件中。我也发现,虽然传感器的值一般都很准确,但是,偶尔也会出现返回不正确读数的情况。这个传感器脚本被修改为不向 MySQL 数据库中写入与前值差异非常大的值。同样也在配置文件中写入了连续读取的温度/湿度之间允许的最大差异值,如果读取的值处于这些限制值以外,这些值写不会提交到数据库中。

虽然,做这个自动调节器似乎花费了很多努力,但是,这意味着,记录到 MySQL 数据库的数据是有效的、可用于进一步去分析识别用户使用模式的有用数据。可以用多种图形方式去展示来自 MySQL 数据库中的数据,而我决定使用 Google Chart 在一个 Web 页面上显示数据。

添加一个婴儿监视摄像头

树莓派开放的性能意味着我可以不断地为它增加功能 —— 并且我有大量的未使用的可用 GPIO 针脚。我的下一个创意是去添加一个摄像头模块,将它放在孩子的卧室中,配置它去监视婴儿。

我需要一个能够在黑暗环境中工作的摄像头,而 Pi Noir 摄像头模块是非常适合这种条件的。Pi Noir 除了没有红外过滤之外,同样也是树莓派常用的摄像头模块。这意味着它在白天时的图像可能有点偏紫色,但是它可以在黑暗中借助红外灯来显示图像。

现在我需要一个红外光源。由于树莓派非常流行,并且进入门槛很低,因此它有大量的外围配件和插件。也有适合它的各种红外光源,我注意到的其中一个是 Bright Pi。它可以从树莓派上供电,并且它很适合为树莓派的摄像头模块提供红外光和普通光。它唯一的缺点是太考验我的焊接技能了。

我的焊接技能还是不错的,但是可能花费的时间比其他人更长。我成功地连接了外壳上所有的红外 LEDs,并将它们连接到树莓派的 GPIO 针脚上。这意味着树莓派能够编程控制红外 LED 是否点亮,以及它的亮度。

通过一个 Web 流去公开捕获的视频也很有意义,因为这样我就可以从 Web 页面上查看温度和湿度的读数图表。进一步研究之后,我选择了一个使用 M-JPEG 捕获器的 流软件。通过 Web 页面公开 JPG 源,我可以在我的智能手机上去连接摄像头查看程序,去查看摄像头的输出。

做最后的修饰

没有哪个树莓派项目都已经完成了还没有为它选择一个合适的外壳,并且它有各种零件。在大量搜索和比较之后,有了一个显然的 赢家:SmartPi 的乐高积木式外壳。乐高的兼容性可以让我去安装温度/湿度传感器和摄像头。下面是最终的成果图:

在这以后,我对我的这个作品作了一些改变和更新:

  • 我将它从树莓派 2 Model B 升级到了树莓派 3,这意味着我可以使用 USB WiFi 模块。
  • 我用一个 TP-Link HS110 智能插头替换了 Orvibo S20。
  • 我也将树莓派插到了一个智能插头上,这样我就可以远程重启/重置它了。
  • 我从树莓派上将 MySQL 数据库移走了,它现在运行在一个 NAS 设备上的容器中。
  • 我增加了一个非常 灵活的三角夹,这样我就可以调整到最佳角度。
  • 我重新编译了 USB WiFi 模块,禁用了板载 LED 指示灯,这就是升级到树莓派 3 的其中一个好处。
  • 我因此为我的第二个孩子设计了另外一个监视器。
  • 因为没有时间去折腾,我为我的第三个孩子购买了夜用摄像头。

想学习更多的东西吗?所有的代码都在 我的 GitHub 页面上。

想分享你的树莓派项目吗?将你的故事和创意发送给我们。

via: https://opensource.com/article/18/3/build-baby-monitor-raspberry-pi
作者:Jonathan Ervine 译者:qhwdw 校对:wxy
本文由 LCTT 原创编译,Linux中国 荣誉推出

在未经修改的NES主机上玩SNES游戏

模拟器一般是运行在较新的设备上的,用来模拟较旧的设备上的软件。但来自宾夕法尼亚州匹兹堡的计算机科学家Tom Murphy VII通过“逆向模拟”SNES来改变这一过程。他在一个NES设备上成功模拟SNES游戏的运行,其中的关键是通过将树莓派嵌入到NES游戏卡带中来,树莓派模仿SNES游戏,并将图形转换为NES硬件可以显示的形式。至于这么做有什么实际意义?可能并不大,研究纯属好奇和好玩,这就足够了!

汤姆在这个引人入胜的视频中解释了他必须解决的许多技术问题:


该项目需要一个定制的电路板,包括一块树莓派、一个重新编程的NES PPU芯片和一个Nintendo CIC内容保护芯片。

汤姆逆向模拟的关键在于以某种方式欺骗未经修改的NES运行SNES发布冠军超级马里奥世界,他通过将树莓派嵌入到NES游戏卡带中来实现。树莓派模仿SNES游戏,并将图形转换为NES硬件可以显示的形式。

下面的视频制作,更详细地解释了该项目:

 

 

用树莓派自制 MIDI 键盘

MAKER:midiIdentifier/译:趣无尽 Cherry(转载请注明出处)
本教程将手把手教你从零开始自制属于你自己的 MIDI/钢琴/音乐/歌曲键盘。这是一个基于树莓派的开源项目,其中所需的文件在本项目文件库中可以找到。

 

 

如果你是70后、80后,你会认出部分的设计。我们的灵感主要来自Apple II。标志性的特点有底部正面略微向上的角度,以及略微向上倾斜的键盘(如图)。

物件清单

1、树莓派3B型 × 1
2、电容式触摸显示屏7寸× 1(Waveshare 树莓派 3.5英寸触摸屏 TFT LCD(A)320 * 480)
3、扬声器 × 2
4、Midi USB 键盘 × 1
5、胶合板 × 若干(约3mm厚)
6、热熔胶 × 1

软件依赖

在为midiIdentifier安装实际软件之前,首先需要安装许多依赖项。其中大部分都可以使用“apt-get”工具进行安装,该工具预装在每个Raspbian OS发行版上。在下面你可以找到安装相应依赖项所需的特定命令,包括依赖项功能的简要说明。

依赖项说明如下:
1、一个干净的Raspbian OS
2、Fluidsynth合成软件(播放音乐的音频输出和音频生成所需):

sudo apt-get install fluidsynth

从以下URL下载Fluidsynth声音字体:
https://sourceforge.net/p/fluidsynth/wiki/SoundFont/

SOUNDFONT,顾名思义,就是“声音字体”。档案储存为 .SF 或 .SF2。 它是几年前 ( 2000年 & 2001年第二版本 ) 由 新加坡创新公司 Creative Technology 在中档声卡上 (EMU SoundBlaster)使用的音色库技术。它是用字符合成的,一个Sound Fond表现出一组音乐符号。用MIDI键盘输入乐符时,会自动记下MIDI的参数,最后在Sound Fond中查找,当你需要它时,就下载到声卡上。

设置Fluidsynth自动启动:

crontab -e

添加以下行:

@reboot /usr/bin/screen -dm /usr/bin/fluidsynth -a alsa -m alsa_seq -i -s -o "shell.port=9988" -g 2 /FluidR3_GM.sf2

3、安装Py-Audio(各种声音输入和输出功能所需):

sudo apt-get install python3-pyaudio

4、Telnet(需要连接到负责音频输出的Fluidsynth服务器):

sudo apt-get install telnet

5、Screen(作为后台任务所运行的应用程序):

sudo apt-get install screen

6、Git(需要下载midiIdentifier软件/克隆代码库)

sudo apt-get install git

显示设置

需要对 Raspbian OS 初始配置,以便支持触摸屏。具体需要对启动配置文件进行各种更改。请注意,对这些配置文件的随意的更改可能会使树莓派无法正常启动。

1、使用文本编辑器(nano)打开启动配置文件。需要root权限(sudo)才能对文件进行更改。用于打开和编辑文件的命令如下:

sudo nano /boot/config.txt

添加以下行(如果已存在,请删除现有行)

max_usb_current=1
hdmi_group=2
hdmi_mode=87
hdmi_cvt 1024 600 60 6 0 0 0
hdmi_drive=1

请注意不要在“=”符号前后包含任何空格。
保存并关闭文件。如果你使用的是nano,请执行以下操作:

Press CTRL + X
Type “Y” and press Enter

2、将显示器随机连接到HDMI和树莓派的USB端口上。
3、打开背光(开关在显示屏的背面)。
4、重启树莓派。

MidiIdentifier 软件

在下文中,我们假设应用程序将在名为“pi”的用户下运行。如果不是这种情况,则需要相应地调整目录路径(/home/[你的用户名])。
1、使用以下命令从Github克隆midiIdentifier仓库:

2、将仓库添加到Pythonpath。
打开文件~/.bashrc(使用 nano,方法参考上一步)。
添加以下行:
PYTHONPATH="${PYTHONPATH}:/home/pi/workspace/midiIdentifier/src"
保存文件,然后使用以下命令重新加载它:
. ~/.bashrc<br>

注意命令中的空格,重启树莓派。

3、设置应用程序的自动启动。
在主目录中创建一个名为“start_gui.sh”的文件,并添加以下行:

#!/bin/bash
sleep 3
cd /home/pi/workspace/midiIdentifier/src/guiMI
python3 /home/pi/workspace/midiIdentifier/src/guiMI/gui.py
sleep 30

打开文件 ~/.config/lxsession/LXDE-pi/autostart 并添加以下行:

@lxterminal -e /home/pi/start_gui.sh

4、为了让 midiIdentifier 跑起来,需要将一组midi文件手动复制到midi目录中。为避免侵犯版权,我们的git仓库中不包含这些文件。但是,可以通过Google搜索从各种在线资源下载它们。下载文件后,需要将它们复制到以下目录中:

/home/pi/workspace/midiIdentifier/files/new_midi

在此之后,需要使用以下命令解析midi文件:

python3 /home/pi/workspace/midiIdentifier/src/converterMI/midiToText.py

5、重启树莓派。

恭喜你,你做到了!到现在为止,midiIdentifier 应该能正常运行啦!

制作外壳

 

 

 

 

 

切割屏幕框和整个案例所需的所有文件都可以在本项目文件库中下载到。
http://maker.quwj.com/project/67

可选:如果你想修改我们的构建模型或者你只是对设计激光切割机文件的过程感兴趣,请继续阅读:

在纸上绘制基本草图以便了解尺寸,我们使用Adobe Illustrator设计激光切割机的文件(你可以从网站获得1周的测试版本)。然而,我们没有绘制每一个凹槽,这里有一个很棒的免费在线工具可以帮助你,Joinery。我们将AI文件导出为SVG并将其导入Joinery,我们将不同的边缘相互连接。 Joinery允许你定义不同角度的配置文件,以便稍后重复使用,并允许保存项目。
因此,Joinery资料和切割资料如下。如果你想对我们的设计进行微小的更改,这些特别有用,当涉及到切割的公差等时,它们比adobe illustrator文件更容易更改。
midiIdentifier_lasercutter_files.zip
midiIdentifier_joinery_files.zip

将所有一切组合在一起

 

 

安装好树莓派上的软件(并测试它是否正常工作)并切割所有胶合板,你就可以开始组合软件和硬件了。

1、首先,除了背面的板子外,你应该将整个外壳组合在一起。此外,不要连接屏幕盒,这将是最后一步。如果你想用胶水加固,你可以试试。
2、将钢琴键从后面嵌入到外壳,确保将其嵌入成功。将它靠在木头上并测量需要切割的部件的高度以将其固定到位。切割这些碎片(2到3片)并将它们固定在钢琴键和盒子的底座上,将钢琴键保持在应该放置的位置,并确保按下琴键后不会移动。
3、安装完板子后,随后将扬声器的活动铰链放在主箱体内。你可以使用热熔胶或胶水。在下面放一些木块做支撑,这样即使稍后放置盒子,它们也会保持水平。
4、将整个屏幕盒(内部屏幕,通过盒子底部孔突出的电缆)通过活动铰链连接到主体箱上。
5、在主体箱内部添加一个木块,以便在折叠到主体箱时,屏幕盒仍可以保持水平位置(如图)。支撑木块的地方可以用一段铁管支撑屏幕,以便屏幕可以在不同的角度直立。
6、将扬声器安装到木板上(我们使用双面胶)。为了方便运输,屏幕和盒子可以折回到主箱体内!
7、最后,将所有电缆连接到树莓派。

就是这样,完成了!希望你喜欢我们的教程!

 

 

 

 

 

树莓派 VNC Viewer 远程桌面配置教程

树莓派实验室在之前介绍过《直接用Windows远程桌面连接树莓派的方法》,使用的是微软的“远程桌面(Remote Desktop Connection)”作为客户端登录树莓派。下面我们介绍使用树莓派官方认证的 RealVNC 客户端登录树莓派的方法。

在开始之前,你需要已经登录树莓派,进入到树莓派命令窗口,通过接上显示器和键鼠直接操作或通过 SSH 登录都可以。

启用树莓派 VNC 服务

在终端输入以下命令进入配置界面。

sudo raspi-config

依次操作:Interfacing Options -> VNC -> Yes。之后系统会提示你是否要安装 VNC 服务,输入 y 之后回车,等待系统自动下载安装完成,一切顺利的话 VNC 服务就启动了!

 

 

 

安装 VNC 客户端

下面去 RealVNC 官网下载 RealVNC Viewer,它是 RealVNC 的客户端,跨平台。下载你需要的平台的客户端版本即可。

https://www.realvnc.com/en/connect/download/viewer/

登录远程桌面

运行 RealVNC Viewer 之后输入树莓派的 IP 地址,通过 ifconfig 命令可以查看。选择连接之后输入树莓派的登录用户名密码,初始用户名 pi,密码为 raspberry。确认之后即可进入树莓派的远程桌面!

 

 

 

 

本文转载自 树莓派实验室

 

树莓派 Linux 系统命令行快捷键

刚入门树莓派时,在 Linux 下使用命令操作的时候,光标的移动令人头痛。命令输入完了,执行之后发现缺少权限,然后不得不移动光标到行首,而命令又极长……当我学会了命令行相关的快捷键之后,不仅效率提高了,更让我喜欢上了命令行这种操作方式。

常用

  • Ctrl+左右键:在单词之间跳转
  • Ctrl+a:跳到本行的行首
  • Ctrl+e:跳到页尾
  • Ctrl+u:删除当前光标前面的文字 (还有剪切功能)
  • Ctrl+k:删除当前光标后面的文字(还有剪切功能)
  • Ctrl+L:进行清屏操作
  • Ctrl+y:粘贴Ctrl+u或ctrl+k剪切的内容
  • Ctrl+w:删除光标前面的单词的字符
  • Alt – d :由光标位置开始,往右删除单词。往行尾删

说明

  • Ctrl – k: 先按住 Ctrl 键,然后再按 k 键;
  • Alt – k: 先按住 Alt 键,然后再按 k 键;
  • M – k:先单击 Esc 键,然后再按 k 键。

移动光标

  • Ctrl – a :移到行首
  • Ctrl – e :移到行尾
  • Ctrl – b :往回(左)移动一个字符
  • Ctrl – f :往后(右)移动一个字符
  • Alt – b :往回(左)移动一个单词
  • Alt – f :往后(右)移动一个单词
  • Ctrl – xx :在命令行尾和光标之间移动
  • M-b :往回(左)移动一个单词
  • M-f :往后(右)移动一个单词

编辑命令

  • Ctrl – h :删除光标左方位置的字符
  • Ctrl – d :删除光标右方位置的字符(注意:当前命令行没有任何字符时,会注销系统或结束终端)
  • Ctrl – w :由光标位置开始,往左删除单词。往行首删
  • Alt – d :由光标位置开始,往右删除单词。往行尾删
  • M – d :由光标位置开始,删除单词,直到该单词结束。
  • Ctrl – k :由光标所在位置开始,删除右方所有的字符,直到该行结束。
  • Ctrl – u :由光标所在位置开始,删除左方所有的字符,直到该行开始。
  • Ctrl – y :粘贴之前删除的内容到光标后。
  • ctrl – t :交换光标处和之前两个字符的位置。
  • Alt + . :使用上一条命令的最后一个参数。
  • Ctrl – _ :回复之前的状态。撤销操作。

Ctrl -a + Ctrl -k 或 Ctrl -e + Ctrl -u 或 Ctrl -k + Ctrl -u 组合可删除整行。

Bang(!)命令

  • !! :执行上一条命令。
  • ^foo^bar :把上一条命令里的foo替换为bar,并执行。
  • !wget :执行最近的以wget开头的命令。
  • !wget:p :仅打印最近的以wget开头的命令,不执行。
  • !$ :上一条命令的最后一个参数, 与 Alt - . 和 $_ 相同。
  • !* :上一条命令的所有参数
  • !*:p :打印上一条命令是所有参数,也即 !*的内容。
  • ^abc :删除上一条命令中的abc。
  • ^foo^bar :将上一条命令中的 foo 替换为 bar
  • ^foo^bar^ :将上一条命令中的 foo 替换为 bar
  • !-n :执行前n条命令,执行上一条命令: !-1, 执行前5条命令的格式是: !-5

查找历史命令

  • Ctrl – p :显示当前命令的上一条历史命令
  • Ctrl – n :显示当前命令的下一条历史命令
  • Ctrl – r :搜索历史命令,随着输入会显示历史命令中的一条匹配命令,Enter键执行匹配命令;ESC键在命令行显示而不执行匹配命令。
  • Ctrl – g :从历史搜索模式(Ctrl – r)退出。

控制命令

  • Ctrl – l :清除屏幕,然后,在最上面重新显示目前光标所在的这一行的内容。
  • Ctrl – o :执行当前命令,并选择上一条命令。
  • Ctrl – s :阻止屏幕输出
  • Ctrl – q :允许屏幕输出
  • Ctrl – c :终止命令
  • Ctrl – z :挂起命令

重复执行操作动作

  • M – 操作次数 操作动作 : 指定操作次数,重复执行指定的操作。

转载自 树莓派实验室

在树莓派上安装 Mosquitto 实现 MQTT

MQTT是IBM开发的一个即时通讯协议。MQTT是面向M2M和物联网的连接协议,采用轻量级发布和订阅消息传输机制。Mosquitto是一款实现了 MQTT v3.1 协议的开源消息代理软件,提供轻量级的,支持发布/订阅的的消息推送模式,使设备对设备之间的短消息通信简单易用。
若初次接触MQTT协议,可先理解以下概念:
MQTT协议特点——相比于RESTful架构的物联网系统,MQTT协议借助消息推送功能,可以更好地实现远程控制。
MQTT协议角色——在RESTful架构的物联网系统,包含两个角色客户端和服务器端,而在MQTT协议中包括发布者,代理器(服务器)和订阅者。
MQTT协议消息——MQTT中的消息可理解为发布者和订阅者交换的内容(负载),这些消息包含具体的内容,可以被订阅者使用。
MQTT协议主题——MQTT中的主题可理解为相同类型或相似类型的消息集合。

本文说明如何在树莓派上安装Mosquitto。本文通过两个简单的例子说明树莓派中如何使用MQTT协议实现消息订阅,这些例子包括Mosquitto_sub指令实现消息订阅和paho-python扩展库实现GPIO端口的远程控制。本文中使用了两个工具——Mosquitto paho-python,其中Mosquitto是一款实现了 MQTT v3.1 协议的开源消息代理软件,提供轻量级的,支持发布/订阅的的消息推送模式,使设备对设备之间的消息通信简单易用;另外,paho-python是一个符合MQTT v3.1协议的客户端,paho-python可连接MQTT代理服务器、发布消息、订阅消息和获得推送消息。

1 在树莓派上安装Mosquitto

在树莓派上安装Mosquitto和其他平台类似,如果在树莓派平台直接编译时间可能会稍长些。Mosquitto源代包不大,所以编译时间尚可忍受。

1.1 安装

截止2014年9月,最新版本为mosquitto-1.3.4。在树莓派中新建一个目录,例如software。

# 下载源代码包
wget http://mosquitto.org/files/source/mosquitto-1.3.4.tar.gz
# 解压
tar zxfv mosquitto-1.3.4.tar.gz
# 进入目录
cd mosquitto-1.3.4
# 编译
make
# 安装
sudo make install

1.2 安装注意点

编译找不到openssl/ssl.h
解决方法:安装openssl

sudo apt-get install libssl-dev

编译过程找不到ares.h
解决方法:修改config.mk中的WITH_SRV:=yes,改为WITH_SRV:=yes

使用过程中找不到libmosquitto.so.1
error while loading shared libraries: libmosquitto.so.1: cannot open shared object file: No such file or directory

解决方法:修改libmosquitto.so位置

# 创建链接
sudo ln -s /usr/local/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1
# 更新动态链接库
sudo ldconfig

make: g++:命令未找到
解决方法:安装g++编译器

2 简单的例子

设计一个简单的测试案例,在PC机上运行MQTT代理服务器,而树莓派订阅主题为gpio的消息,PC机发布同主题消息,消息的内容为JSON数据包,数据包格式为{“index”:17,“value”:0},index代表树莓派GPIO的编号,value代表打开或关闭状态。

 

本例中PC机IP地址为 192.168.1.110,树莓派的IP地址为192.168.1.106

2.1 在PC机中开启MQTT服务

mosquitto -v

2.2 在树莓派中订阅消息

-h指定MQTT代理服务器主机,指向PC机IP地址192.168.1.110

mosquitto_sub -v -t gpio -h 192.168.1.110

2.3 在PC机中发布消息

-h指定MQTT代理服务器主机,指向PC机IP地址192.168.1.110

mosquitto_pub -t gpio -h 192.168.1.110 -m "{\"pin\":17,\"value\":0}"

2.4 消息被推送到树莓派中

最后在树莓派中输出以下内容:

gpio {"index":17,"value":0}

在PC机MQTT服务器控制台中输出

1410600001: mosquitto version 1.3.4 (build date 2014-09-13 15:55:06+0800) starting
1410600001: Using default config.
1410600001: Opening ipv4 listen socket on port 1883.
1410600001: Opening ipv6 listen socket on port 1883.
1410600062: New connection from 192.168.1.106 on port 1883.
1410600062: New client connected from 192.168.1.106 as mosqsub/3063-raspberryp (c1, k60).
1410600062: Sending CONNACK to mosqsub/3063-raspberryp (0)
1410600062: Received SUBSCRIBE from mosqsub/3063-raspberryp
1410600062: gpio (QoS 0)
1410600062: mosqsub/3063-raspberryp 0 gpio
1410600062: Sending SUBACK to mosqsub/3063-raspberryp
1410600122: Received PINGREQ from mosqsub/3063-raspberryp
1410600122: Sending PINGRESP to mosqsub/3063-raspberryp
1410600152: New connection from 192.168.1.110 on port 1883.
1410600152: New client connected from 192.168.1.110 as mosqpub/9793-EasyARM (c1, k60).
1410600152: Sending CONNACK to mosqpub/9793-EasyARM (0)
1410600152: Received PUBLISH from mosqpub/9793-EasyARM (d0, q0, r0, m0, 'gpio', ... (22 bytes))
1410600152: Sending PUBLISH to mosqsub/3063-raspberryp (d0, q0, r0, m0, 'gpio', ... (22 bytes))
1410600152: Received DISCONNECT from mosqpub/9793-EasyARM
1410600182: Received PINGREQ from mosqsub/3063-raspberryp
1410600182: Sending PINGRESP to mosqsub/3063-raspberryp

3 使用MQTT远程控制GPIO

下面借助python-gpio扩展库,通过消息推送的方式实现GPIO端口的远程控制。

3.1 安装paho-mqtt

使用pip工具安装paho-mqtt,输入以下指令即可:

sudo pip install paho-mqtt

3.2 树莓派订阅代码 simple.py

# -*- coding: utf-8 -*-  
import paho.mqtt.client as mqtt
import RPi.GPIO as GPIO
import json
  
# BCM GPIO编号
pins = [17,18,27,22,23,24,25,4]
def gpio_setup():
    # 采用BCM编号
    GPIO.setmode(GPIO.BCM)
    # 设置所有GPIO为输出状态,且输出低电平
    for pin in pins:
        GPIO.setup(pin, GPIO.OUT)
        GPIO.output(pin, GPIO.LOW)
         
def gpio_destroy():
    for pin in pins:
        GPIO.output(pin, GPIO.LOW)
        GPIO.setup(pin, GPIO.IN)
         
# 连接成功回调函数
def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))
    # 连接完成之后订阅gpio主题
    client.subscribe("gpio")
  
# 消息推送回调函数
def on_message(client, userdata, msg):
    print(msg.topic+" "+str(msg.payload))
    # 获得负载中的pin 和 value
    gpio = json.loads(str(msg.payload))
  
    if gpio['pin'] in pins:
        if gpio['value'] == 0:
            GPIO.output(gpio['pin'], GPIO.LOW)
        else:
            GPIO.output(gpio['pin'], GPIO.HIGH)
  
if __name__ == '__main__':
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    gpio_setup()
     
    try:
        # 请根据实际情况改变MQTT代理服务器的IP地址
        client.connect("192.168.1.110", 1883, 60)
        client.loop_forever()
    except KeyboardInterrupt:
        client.disconnect()
        gpio_destroy()

3.3 启动服务并发布消息

在PC机中启动MQTT代理服务

mosquitto -v

在树莓派中运行脚本

sudo python simple.py

在PC机中发布消息

# 打开GPIO17
mosquitto_pub -h 192.168.1.110 -t gpio -m "{\"pin\":17,\"value\":1}"
# 关闭GPIO17
mosquitto_pub -h 192.168.1.110 -t gpio -m "{\"pin\":17,\"value\":0}"

运行结果
树莓派GPIO17根据PC机推送的消息点亮或熄灭。

4 总结

本文说明了如何在树莓派中使用MQTT客户端,通过paho-mqtt实现GPIO的远程控制。本例在局域网中运行并能不能体现出MQTT协议在远程控制中的优越性。后期还将花更多的时间实践和分析MQTT协议。

转自:https://blog.csdn.net/xukai871105/article/details/39255089

相关资料:
1、https://blog.csdn.net/xukai871105/article/details/39252653
2、http://blog.csdn.net/shagoo/article/details/7910598
3、https://www.jianshu.com/p/f8d824afbe3d

 

 

树莓派使用 Nokia 5110 屏幕显示网速温度

Nokia 5110
长上图这样。

驱动
PCD8544

资料
Google 一搜各种博客都有介绍,毕竟我不是学硬件的,底层什么的就不说了。好玩就行。

引脚

rst:外部复位引脚
ce:显示屏使能引脚
dc:数据/命令引脚
din:串行数据输入端
clk:串行时钟输入端
vcc:电源引脚
bl: 亮度调节
gnd:接地

先看看驱动代码

修改自(Adafruit),这里用的是 BCM 编码。

# coding:utf-8
import time
import Adafruit_GPIO as GPIO
import Adafruit_GPIO.SPI as SPI
 
LCDWIDTH = 84
LCDHEIGHT = 48
ROWPIXELS = LCDHEIGHT//6
PCD8544_POWERDOWN = 0x04
PCD8544_ENTRYMODE = 0x02
PCD8544_EXTENDEDINSTRUCTION = 0x01
PCD8544_DISPLAYBLANK = 0x0
PCD8544_DISPLAYNORMAL = 0x4
PCD8544_DISPLAYALLON = 0x1
PCD8544_DISPLAYINVERTED = 0x5
PCD8544_FUNCTIONSET = 0x20
PCD8544_DISPLAYCONTROL = 0x08
PCD8544_SETYADDR = 0x40
PCD8544_SETXADDR = 0x80
PCD8544_SETTEMP = 0x04
PCD8544_SETBIAS = 0x10
PCD8544_SETVOP = 0x80
FONT = {
  ' ': [0x00, 0x00, 0x00, 0x00, 0x00],
  '!': [0x00, 0x00, 0x5f, 0x00, 0x00],
  '"': [0x00, 0x07, 0x00, 0x07, 0x00],
  '#': [0x14, 0x7f, 0x14, 0x7f, 0x14],
  '$': [0x24, 0x2a, 0x7f, 0x2a, 0x12],
  '%': [0x23, 0x13, 0x08, 0x64, 0x62],
  '&': [0x36, 0x49, 0x55, 0x22, 0x50],
  "'": [0x00, 0x05, 0x03, 0x00, 0x00],
  '(': [0x00, 0x1c, 0x22, 0x41, 0x00],
  ')': [0x00, 0x41, 0x22, 0x1c, 0x00],
  '*': [0x14, 0x08, 0x3e, 0x08, 0x14],
  '+': [0x08, 0x08, 0x3e, 0x08, 0x08],
  ',': [0x00, 0x50, 0x30, 0x00, 0x00],
  '-': [0x08, 0x08, 0x08, 0x08, 0x08],
  '.': [0x00, 0x60, 0x60, 0x00, 0x00],
  '/': [0x20, 0x10, 0x08, 0x04, 0x02],
  '0': [0x3e, 0x51, 0x49, 0x45, 0x3e],
  '1': [0x00, 0x42, 0x7f, 0x40, 0x00],
  '2': [0x42, 0x61, 0x51, 0x49, 0x46],
  '3': [0x21, 0x41, 0x45, 0x4b, 0x31],
  '4': [0x18, 0x14, 0x12, 0x7f, 0x10],
  '5': [0x27, 0x45, 0x45, 0x45, 0x39],
  '6': [0x3c, 0x4a, 0x49, 0x49, 0x30],
  '7': [0x01, 0x71, 0x09, 0x05, 0x03],
  '8': [0x36, 0x49, 0x49, 0x49, 0x36],
  '9': [0x06, 0x49, 0x49, 0x29, 0x1e],
  ':': [0x00, 0x36, 0x36, 0x00, 0x00],
  ';': [0x00, 0x56, 0x36, 0x00, 0x00],
  '<': [0x08, 0x14, 0x22, 0x41, 0x00], '=': [0x14, 0x14, 0x14, 0x14, 0x14], '>': [0x00, 0x41, 0x22, 0x14, 0x08],
  '?': [0x02, 0x01, 0x51, 0x09, 0x06],
  '@': [0x32, 0x49, 0x79, 0x41, 0x3e],
  'A': [0x7e, 0x11, 0x11, 0x11, 0x7e],
  'B': [0x7f, 0x49, 0x49, 0x49, 0x36],
  'C': [0x3e, 0x41, 0x41, 0x41, 0x22],
  'D': [0x7f, 0x41, 0x41, 0x22, 0x1c],
  'E': [0x7f, 0x49, 0x49, 0x49, 0x41],
  'F': [0x7f, 0x09, 0x09, 0x09, 0x01],
  'G': [0x3e, 0x41, 0x49, 0x49, 0x7a],
  'H': [0x7f, 0x08, 0x08, 0x08, 0x7f],
  'I': [0x00, 0x41, 0x7f, 0x41, 0x00],
  'J': [0x20, 0x40, 0x41, 0x3f, 0x01],
  'K': [0x7f, 0x08, 0x14, 0x22, 0x41],
  'L': [0x7f, 0x40, 0x40, 0x40, 0x40],
  'M': [0x7f, 0x02, 0x0c, 0x02, 0x7f],
  'N': [0x7f, 0x04, 0x08, 0x10, 0x7f],
  'O': [0x3e, 0x41, 0x41, 0x41, 0x3e],
  'P': [0x7f, 0x09, 0x09, 0x09, 0x06],
  'Q': [0x3e, 0x41, 0x51, 0x21, 0x5e],
  'R': [0x7f, 0x09, 0x19, 0x29, 0x46],
  'S': [0x46, 0x49, 0x49, 0x49, 0x31],
  'T': [0x01, 0x01, 0x7f, 0x01, 0x01],
  'U': [0x3f, 0x40, 0x40, 0x40, 0x3f],
  'V': [0x1f, 0x20, 0x40, 0x20, 0x1f],
  'W': [0x3f, 0x40, 0x38, 0x40, 0x3f],
  'X': [0x63, 0x14, 0x08, 0x14, 0x63],
  'Y': [0x07, 0x08, 0x70, 0x08, 0x07],
  'Z': [0x61, 0x51, 0x49, 0x45, 0x43],
  '[': [0x00, 0x7f, 0x41, 0x41, 0x00],
  '\\': [0x02, 0x04, 0x08, 0x10, 0x20],
  ']': [0x00, 0x41, 0x41, 0x7f, 0x00],
  '^': [0x04, 0x02, 0x01, 0x02, 0x04],
  '_': [0x40, 0x40, 0x40, 0x40, 0x40],
  '`': [0x00, 0x01, 0x02, 0x04, 0x00],
  'a': [0x20, 0x54, 0x54, 0x54, 0x78],
  'b': [0x7f, 0x48, 0x44, 0x44, 0x38],
  'c': [0x38, 0x44, 0x44, 0x44, 0x20],
  'd': [0x38, 0x44, 0x44, 0x48, 0x7f],
  'e': [0x38, 0x54, 0x54, 0x54, 0x18],
  'f': [0x08, 0x7e, 0x09, 0x01, 0x02],
  'g': [0x0c, 0x52, 0x52, 0x52, 0x3e],
  'h': [0x7f, 0x08, 0x04, 0x04, 0x78],
  'i': [0x00, 0x44, 0x7d, 0x40, 0x00],
  'j': [0x20, 0x40, 0x44, 0x3d, 0x00],
  'k': [0x7f, 0x10, 0x28, 0x44, 0x00],
  'l': [0x00, 0x41, 0x7f, 0x40, 0x00],
  'm': [0x7c, 0x04, 0x18, 0x04, 0x78],
  'n': [0x7c, 0x08, 0x04, 0x04, 0x78],
  'o': [0x38, 0x44, 0x44, 0x44, 0x38],
  'p': [0x7c, 0x14, 0x14, 0x14, 0x08],
  'q': [0x08, 0x14, 0x14, 0x18, 0x7c],
  'r': [0x7c, 0x08, 0x04, 0x04, 0x08],
  's': [0x48, 0x54, 0x54, 0x54, 0x20],
  't': [0x04, 0x3f, 0x44, 0x40, 0x20],
  'u': [0x3c, 0x40, 0x40, 0x20, 0x7c],
  'v': [0x1c, 0x20, 0x40, 0x20, 0x1c],
  'w': [0x3c, 0x40, 0x30, 0x40, 0x3c],
  'x': [0x44, 0x28, 0x10, 0x28, 0x44],
  'y': [0x0c, 0x50, 0x50, 0x50, 0x3c],
  'z': [0x44, 0x64, 0x54, 0x4c, 0x44],
  '{': [0x00, 0x08, 0x36, 0x41, 0x00],
  '|': [0x00, 0x00, 0x7f, 0x00, 0x00],
  '}': [0x00, 0x41, 0x36, 0x08, 0x00],
  '~': [0x10, 0x08, 0x08, 0x10, 0x08],
  '\x7f': [0x00, 0x7e, 0x42, 0x42, 0x7e],
}
X = 13
Y = 5
 
class PCD8544(object):
    """Nokia 5110/3310 PCD8544-based LCD display."""
 
    def __init__(self, dc, rst, sclk=None, din=None, cs=None, gpio=None, spi=None, vcc=None, bl=None):
        self._sclk = sclk
        self._din = din
        self._dc = dc
        self._cs = cs
        self._rst = rst
        self._gpio = gpio
        self._spi = spi
        self._buffer = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFF, 0xFC, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0xC0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x87, 0x8F, 0x9F, 0x9F, 0xFF, 0xFF, 0xFF, 0xC1, 0xC0, 0xE0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF1, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x0F, 0x87, 0xE7, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x3F, 0xF9, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7E, 0x3F, 0x3F, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0xE0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x1F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
        if self._gpio is None:
            self._gpio = GPIO.get_platform_gpio()
            self._gpio.setup(vcc, GPIO.OUT)
            self._gpio.setup(bl, GPIO.OUT)
            self._gpio.output(vcc, 1)
            self._gpio.output(bl, 1)
        if self._rst is not None:
            self._gpio.setup(self._rst, GPIO.OUT)
        # Default to bit bang SPI.
        if self._spi is None:
            self._spi = SPI.BitBang(self._gpio, self._sclk, self._din, None, self._cs)
        # Set pin outputs.
        self._gpio.setup(self._dc, GPIO.OUT)
        # Initialize buffer to Adafruit logo.
 
    def command(self, c):
        """Send command byte to display."""
        # DC pin low signals command byte.
        self._gpio.set_low(self._dc)
        self._spi.write()
 
    def extended_command(self, c):
        """Send a command in extended mode"""
        # Set extended command mode
        self.command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION)
        self.command(c)
        # Set normal display mode.
        self.command(PCD8544_FUNCTIONSET)
        self.command(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL)
 
    def begin(self, contrast=40, bias=4):
        """Initialize display."""
        self.reset()
        # Set LCD bias.
        self.set_bias(bias)
        self.set_contrast(contrast)
 
    def reset(self):
        """Reset the display"""
        if self._rst is not None:
            # Toggle RST low to reset.
            self._gpio.set_low(self._rst)
            time.sleep(0.1)
            self._gpio.set_high(self._rst)
 
    def display(self):
        """Write display buffer to physical display."""
        # TODO: Consider support for partial updates like Arduino library.
        # Reset to position zero.
        self.command(PCD8544_SETYADDR)
        self.command(PCD8544_SETXADDR)
        # Write the buffer.
        self._gpio.set_high(self._dc)
        self._spi.write(self._buffer)
 
    def clear(self):
        """Clear contents of image buffer."""
        self._buffer = [0] * (LCDWIDTH * LCDHEIGHT // 8)
 
    def set_contrast(self, contrast):
        """Set contrast to specified value (should be 0-127)."""
        contrast = max(0, min(contrast, 0x7f)) # Clamp to values 0-0x7f
        self.extended_command(PCD8544_SETVOP | contrast)
 
    def set_bias(self, bias):
        """Set bias"""
        self.extended_command(PCD8544_SETBIAS | bias)
 
    def draw_str(self, y, s):
        """修改显示数据,y 为第几行,s 为要显示的数据"""
        if (y >= Y ) or (y < 0):
            return False
        x = 0
        for c in s[0:14]:
            try:
                self._buffer[y*84+x*6: y*84+x*6 + 6] = FONT + [0]
            except KeyError:
                pass
            x += 1
 
    def draw_char(self, x, y):
        pass
 
    def quit(self):
        self._gpio.cleanup()

接线(BCM)

dc 13
rst 5
sclk 26
din 19
cs 6
vcc 20
bl 21
gnd 0v

显示信息

网速
显示路由器的网速,电脑网速就没必要了。
我用的是老毛子固件,所以用这个固件的可以参考我的代码。

代码量不大,我就没写注释了。

# coding:utf-8
import requests
import time
from math import fabs
from base64 import b64encode
# from demjson import decode
 
class RaspberryMonitorNetSpeed:
    url = 'http://192.168.123.1/update.cgi?output=netdev'
    headers = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Cache-Control': 'max-age=0',
            # 'Connection':'keep-alive',
            'Connection': 'close',
            'Cookie': 'n56u_cookie_bw_rt_tab=WAN',
            'Host': '192.168.123.1',
            'Upgrade-Insecure-Requests': '1',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36',
        }
    # 最近一次请求时间
    last_time = 0
    # 最近一次请求的下行数据总量
    last_rbytes = 0
    # 最近一次请求的上行数据总量
    last_tbytes = 0
 
    def __init__(self, username, passwd):
        self.headers['Authorization'] = 'Basic '+b64encode((username+':'+passwd).encode()).decode()
        data = self.__get_wan_rx_and_tx()
        self.last_rbytes = data[0]
        self.last_tbytes = data[1]
        self.last_time = data[2]
 
    def set_auth(self, username, passwd):
        self.headers['Authorization'] = 'Basic '+b64encode((username+':'+passwd).encode()).decode()
 
    def __get_wan_rx_and_tx(self):
        text = requests.get(self.url, headers=self.headers).text
        try:
            rx = int(text.split(',')[25].lstrip('rx:').strip(), 16)
            tx = int(text.split(',')[26].lstrip('tx:').rstrip('}\n').strip(), 16)
            new_time = time.time()
        except (IndexError, ValueError, TypeError):
            return False
        return [rx, tx, new_time]
 
    def get_human_speed(self):
        """这里返回的是 M/s 这种网速,[下载,上传]"""
        data = self.__get_wan_rx_and_tx()
        if data:
            down_speed = 0
            up_speed = 0
            try:
                down_speed = self.__bytes_to_humanspeed((data[0] - self.last_rbytes) / (data[2] - self.last_time))
                up_speed = self.__bytes_to_humanspeed((data[1] - self.last_tbytes) / (data[2] - self.last_time))
            except ZeroDivisionError:
                pass
            self.last_rbytes = data[0]
            self.last_tbytes = data[1]
            self.last_time = data[2]
            return down_speed, up_speed
 
    def __bytes_to_humanspeed(self, B):
        absval = fabs(B) / 1024
        megabyte = 1024
        gigabyte = megabyte * 1024
        terabyte = gigabyte * 1024
        # petabyte = terabyte * 1024
        if absval < megabyte:
            return str(round(absval, 2)) + ' KB/s'
        elif absval < gigabyte:
            return str(round(absval / megabyte, 2)) + ' M/s'
        else:
            return str(round(absval / gigabyte, 2)) + ' G/s'
 
    def get_bits_speed(self):
        """这里返回的是 Mbps 这种网速,[下载,上传]"""
        data = self.__get_wan_rx_and_tx()
        if data:
            down_speed = self.__bytes_to_bitrate((data[0] - self.last_rbytes) / (data[2] - self.last_time))
            up_speed = self.__bytes_to_bitrate((data[1] - self.last_tbytes) / (data[2] - self.last_time))
            self.last_rbytes = data[0]
            self.last_tbytes = data[1]
            self.last_time = data[2]
            return down_speed, up_speed
 
    def __bytes_to_bitrate(self, B):
        bits = B * 8
        absval = fabs(bits)
        kilobit = 1000
        megabit = kilobit * 1000
        gigabit = megabit * 1000
        if absval < megabit:
            return str(round(bits / kilobit, 2)) + ' Kbps'
        elif absval < gigabit:
            return str(round(bits / megabit, 2)) + ' Mbps'
        else:
            return str(round(bits / gigabit, 2)) + ' Gbps'
 
if __name__ == '__main__':
    from lcd1602 import LCD1602
    a = RaspberryMonitorNetSpeed('username', 'password')
    lcd = LCD1602()
    while True:
        tmp = a.get_human_speed()
        lcd.lcd_string('u:' + tmp[1], lcd.LCD_LINE_1)
        lcd.lcd_string('d:' + tmp[0], lcd.LCD_LINE_2)
        time.sleep(2)

温度
这里用的是 DTH11,驱动同样参考这个(Adafruit)。

开始显示
代码量同样不大,没写注释。

import time
import datetime
from PCD8544 import PCD8544 as lcd
import threading
import Adafruit_DHT
from speed import RaspberryMonitorNetSpeed as rmn
 
ns = [-1, -1]
th = [-2, -2]
 
def main():
    a = lcd(dc=13, rst=5, sclk=26, din=19, cs=6, vcc=20, bl=21)
    a.begin(contrast=60)
    tmp = threading.Thread(target=network_speed)
    tmp.setDaemon(True)
    tmp.start()
    tmp = threading.Thread(target=temperature_humidity)
    tmp.setDaemon(True)
    tmp.start()
    while True:
        try:
            a.clear()
            # 上传速度
            a.draw_str(0, 'U: ' + str(ns[1]))
            # 下载速度
            a.draw_str(1, 'D: ' + str(ns[0]))
            # 温度
            a.draw_str(2, 'T: ' + str(th[1]) + ' C')
            # 湿度
            a.draw_str(3, 'H: ' + str(th[0]) + '%')
            # 时间
            a.draw_str(4, datetime.datetime.now().__str__()[5:].lstrip('0').split('.')[0])
            a.display()
            time.sleep(1)
        except KeyboardInterrupt:
            a.quit()
            exit(0)
 
def network_speed():
    global ns
    b = rmn('bankroft', '123456')
    while True:
        time.sleep(1)
        ns = b.get_human_speed()
 
def temperature_humidity():
    global th
    pin = 25
    while True:
        time.sleep(10)
        th = Adafruit_DHT.read_retry(11, 25)
 
if __name__ == '__main__':
    main()

运行

依赖
python3

安装 Python 库
Adafruit_GPIO
Adafruit_DHT
requests

运行

python main.py
成果

在树莓派3B 上安装 Windows 10 ARM 版的方法

早先关注我们的朋友可能对《国外开发者尝试在树莓派3上运行Windows 10桌面版》有印象。本文转自 amatfan.com,文末视频来自 daveb778(感谢柠栀和刺分享),给出了如何在树莓派3B上安装Windows10 ARM版,是的,这次并非IoT版,而是功能与PC一致的ARM版。需要注意的是,这个方法并非官方提供的,可用性上会有一些坑,热衷于尝试的玩家可以一试!

准备项目:树莓派3B以上型号,16G以上SD卡,显示器,键盘鼠标,电源。

1.格式化SD卡

2.使用DiskGenius,打开

格式化为2个分区,第一个100MB,格式为FAT32,第二个为NTFS,大小是剩余的全部容量。

下载镜像链接: https://pan.baidu.com/s/11Pwk1QwgNvr8mh_p6y-VpA 密码: tfyp

右键用Windows资源管理器打开

下载软件:DISM++,百度网盘链接: https://pan.baidu.com/s/1Bkq20DWnf7QPs_qMTAw8yg 密码: dgp4

选择:恢复功能:系统还原

目标映像打开刚才打开的ISO文件中的sources\install.wim文件

写入位置选择刚才格式化的大分区

点击确定开始恢复

等待恢复期间,下载UEFI与驱动:

UEFI:下载

驱动:下载

下载后解压打开,找到UEFI中的RaspberryPiPkg\Binary\prebuilt\2018May22-GCC49\RELEASE

将里面全部文件复制进入SD卡小的分区

等待恢复完毕,我们需要手动创建引导文件。请以管理员身份打开cmd
依次输入以下命令:(2,3条顺序可以颠倒。)

bcdboot X:\Windows /s Y: /f UEFI /l zh-cn
bcdedit /store Y:\efi\microsoft\boot\bcd /set {Default} testsigning on
bcdedit /store Y:\efi\microsoft\boot\bcd /set {Default} nointegritychecks on

其中,X是你的NTFS分区,Y是你的FAT分区
以我的电脑为例,我的sd卡的FAT分区是D:,NTFS分区是F:
则我需要输入如下命令:

bcdboot F:\Windows /s D: /f UEFI /l zh-cn
bcdedit /store D:\efi\microsoft\boot\bcd /set {Default} testsigning on
bcdedit /store D:\efi\microsoft\boot\bcd /set {Default} nointegritychecks on

然后安装驱动(更新驱动也是一样的)

其中F是刚才大的NTFS分区,C:\Users\gloom\Downloads\rpi是驱动下载保存的位置

dism /image:F: /add-driver /driver:C:\Users\gloom\Downloads\rpi /forceunsigned

插入树莓派,开机。然后按esc键来到Uefi设置页面

选择 Device Manager

进入Raspberry pi configeration

选择第一个

更改为EL1

退出重启,去除连接树莓派上的键盘,鼠标,等待系统设置完成(插键盘会蓝屏)

接下来设置与普通Windows一样,设置完成就可以使用了!

以下是 daveb778 提供的视频教程:


 

本文来自:树莓派实验室