冒险五:使用电路
当我们在minecraft世界里游戏时,即使使用了编程接口,也只是个虚拟世界。我们跟游戏交互的唯一方式就是使用键盘和鼠标按照开发游戏的工程师们所设计的方式进行操作。
其实还有另外一种方式来跟minecraft进行交互——打破沙盒游戏的限制,把虚拟世界跟现实世界联系起来。这里你很快会发现虚拟和现实的边界变得模糊,游戏体验变得更有创意和激动人心。
在这个冒险任务里,我们要学习如何使用API把minecraft和小型电路连接起来。我们先从连接一盏灯开始,在我们回到家时让灯开始闪烁。然后我们会添加一种特殊的显示器,称作7段显示器。我们可以在玩游戏时用它来显示倒计时或者其他游戏相关的信息。我们还会添加一个按钮,通过按下按钮可以出发minecraft里的各种有趣的事情。最后,我们要把所有这些组合在一起,来制造一个红色的、功能完整的引爆按钮,能够触发定时爆炸,就像图5-1里那样。有了这个,你再也不会为建造任务里清理空间而发愁了,你的朋友们也会为你的新魔法感到惊讶,并请求你帮他们建造自己的引爆按钮。
材料准备
下面这一份清单,列出了这个冒险任务里组成电路需要的所有东西。我们需要一些电子元件,还有一些额外的配件来把电脑和元件连接起来。我们需要的所有配件都在图5-2和5-3里:
- 一块面包板
- 至少4个按钮
- 至少1个任意颜色的LED(如果有更多会更好)
- 一个7段LED显示器
- 10个或更多330欧姆电阻用来配合LED和显示器
- 4个或更多10K欧姆电阻用来配合按钮
- 至少20个pin-to-pin类型的跳接线,或者一些细的实心导线和剥线
- 一个可装2节AA或AAA电池的电池盒
对于使用树莓派的读者:
可以使用socket-to-pin类型的跳接线直接把树莓派上的引脚和面包板上的孔连接起来。不过这有时会比较难搞,而且要数清楚树莓派上的引脚也比较麻烦。在这个冒险任务里,我用的是一个事先焊接好的Adafruit Pi-T-Cobbler,这是一种带形线缆,一端接在树莓派上,另一端直接插在面包板上,上面标有引脚的编号。如果你会焊接,就可以找一个Pi T-Cobbler工具包并自己焊接,这样要便宜很多。图5-2里是用树莓派玩完成这个冒险任务需要的所有东西。
对于使用PC和Mac的读者:
因为PC和Mac电脑不像树莓派一样带有硬件引脚,所以我用Arduino自己组装了一个用于这些电脑的小型硬件平台。你可以用任何Arduino平台来达到同样的目的,前提是要预先加载我特别编写的开源软件,它可以让Arduino模拟树莓派的I/O引脚。你可以在这里了解关于Arduino的信息。在这个任务里,我们要使用Arduino Pro Micro。我们还需要一根USB线把它跟电脑连接起来。
提醒
如果使用Mac电脑,至少需要OS X 10.6以上的系统才能让Arduino正常运行。
david says
我们需要一些源码文件才能完成这个冒险任务。所有这些文件都包含在了从配套网站上下载的新手包里。我在后面也会给出这些源码文件最新版本的下载地址,这样你也可以把它们用在你自己的非minecraft项目和实验里。
准备好所有的软硬件之后,我们就可以开始着手组件第一个电路了。
用面包板建立原型电路
电子工程师给新产品设计电路的时候,他们通常会先制作一些原型电路板,然后才会去批量生产。
定义
原型是某样东西的一个简化版本,用来测试是否正常工作。相比于成千上万的产品来说,如果只制作了一个原型,那么修复起问题来要简单的多。
david says
网上可以找到很多树莓派电脑最初原型的奇妙图片,它们是树莓派基金会的Eben Upton在2006年制作的。大多数复杂的电路板都是从这样的原型开始的,而且可能要经过很多次的调整和修改才最终成为你手上拿到的电路板。你可以在这里看到这些图片。
大多数电子电路都是焊接在一起的,这样元件和电路板之间的连接才能结实耐久。不过,尽管焊接电路板可以成为非常耐用的产品,但是在我们用不同元件进行实验和设计测试电路的时候却没有什么用处,因为要花很多时间来解焊和重新焊接元件。因此工程师们经常使用一种叫做无焊料面包板的设备。
定义
面包板是一种不需要焊接元件就可以制作电路,并且可以反复使用的设备。面包板上有一些小孔,我们可以把导线或者跳线和元件插进去组成电路。最上面和最下面的两排小孔用来供电。通常会有一条红线,用来连接正极(不如3.3v,有时也标注为+或者VCC),还有一条黑线或者蓝线,用来连接0v(或者叫做地线,有时标注为-或者GND)。
图5-4是两张无焊料面包板的照片。左边是一个插了一些元件组成了电路的面包板,右边是一张面包板内部的照片。如果仔细看,你可以看到连接电路的金属条。理解面包板的连接方式很重要,只有这样你才能知道当元件插入之后它们之间是怎样连接组成电路的。
点亮LED的电路
图5-4是一个可以用来测试元件的最简单的电路。要让一个元件工作,必须给它加上一个电压。我们需要把3V的电池连接到面包板顶部和底部的条带上,它们是供电轨。这些轨道贯穿整个面包板,是一种同时给很多元件供电的有效方式。红色元件是发光二极管(LED),是一种我们很快就会用到的灯。带有彩色横条的元件是电阻,底部的黑色设备是按钮。如果从电池开始沿着导线一直走,最终还会回到电池。这是一个完整的电路,如果按下按钮,就会有电流流动,LED会亮起来。
定义
电压是指电路当中两个点之间电能的差异。电压跟水管里的水压很像,正式这种压力让电流在电路中流动。电压的单位是伏特(V)。
发光二极管(LED)在电流通过时会发光。二极管只允许电流从一个方向通过。LED只有在电流向正确的方向流动时才会发光。LED有很多不同的颜色,它有一只短引脚(阴极,或者负极)和一只长引脚(阳极,或者正极),这两个引脚可以帮你辨别在电路中应该如何连接才能让电流通过。
电阻是电路中阻碍电流流动的元件。比如,如果电流太大LED会被破坏,但是如果在电路中添加一个适当阻值的电阻来限制电流的大小,LED就不会有问题。电阻值的单位是欧姆,通常用符号Omega来表示。我们需要选择电阻值大小适当的电阻来限制电路中的电流;电阻的阻值可以通过上面的彩色横条看出来。你可以在这里学习关于电阻彩色代码的知识。
深入电路
图5-4的电路使用了一个电阻器。LED只能承受很小的电流,通常不超过20mA(也就是0.02安培,非常小)。如果LED直接跟电池连接,电路里电流过大,会破坏LED。要防止这种情况,必须添加一个电阻器来限制电路里电流的大小。电阻器的电阻值可以通过它上面的彩色条纹来识别。
如果使用更高的电压,就需要一个阻值更大的电阻器来限制电流。在这个项目里,我已经算好了阻值,不过有很多网站可以帮你计算在不同电压下的阻值,比如这个
定义
电流是指电能通过电路中某个点的速率,类似于水管中水的流速。电流的单位是安培(A),通常简称为“安”。更小的电流单位是“毫安(mA)”。这里有一些关于电路中电流实际流向的有趣的理论,你可以读一下。
挑战
尝试用你自己的元件组成图5-4里的电路,当开关按下时让LED亮起。你需要一个AA或AAA电池盒。注意LED的引脚必须插入正确的位置。如果LED不亮,检查一下你的连线和LED的引脚。
连接电脑
接下来我们要把电路连接到电脑,用python程序来控制LED。要用电脑控制电子元件,需要有一种方式把电脑和电路连接起来,因此我们需要一些通用输入输出(GPIO)接口。
通用输入输出(GPIO)接口是连接到计算机中央处理器的信号。它们不是为了某种特殊的目的而设计的,而是具有通用性,可以被电路设计者用作不同的用途,通常使用了控制或者感知外部电路。
在一些电脑上,比如树莓派,GPIO通过一侧的特殊引脚提供。一个GPIO引脚可以被设置为输入来感知外部电压,或者设置为输出来控制外部电压。树莓派或者Arduino使用的电压是3.3伏,虽然很小,但是可以在这些引脚产生足够的电流来点亮LED或者感知按钮。英国主流的供电电压是240伏,这是很高(也很危险)的电压,而输电塔的电压则高达230,000伏!相比之下,电脑电路里用到的电压是很小的。
计算机是数字机器,也就是说它内部使用数字(?)。现代计算机都是数字式的,使用数字0和1。在计算机上使用GPIO引脚时,0通常表示没有电压(关闭),或者0伏,1表示加上某个电压(在这里就是3.3伏)。使用GPIO引脚感知外部电压时,计算机内部只能用0和1来表示这些电压。接近0伏的电压表示0,接近3.3伏的电压表示1。中间的电压值是灰色地带,被计算机当成0或者1都有可能。
用PC或Mac连接电路
如果使用树莓派,可以直接跳到下一节“控制LED”。因为树莓派本身就带有GPIO引脚,因此是一个用来控制电路的好选择。
PC和Mac电脑没有自带的GPIO引脚,所以我们必须用一个外部的电路板来添加。有很多中方式都可以做到这一点,不过在这本书里,我选择使用小型、预先编程过的Arduino开发板。这本书里不会讲关于Arduino的知识,如果你感兴趣的话可以参考书后附录里的链接。
david says
在后文的步骤中,我假设你已经购买了本章开头提到的已经焊接和编程好的开发板。如果你打算用空板自己焊接和编程,那么你需要按照这个网页上的步骤来进行,并且要加载我为它编写的开源GPIO软件。这个软件,加上新手包里的anyio Python模块,可以让Arduino开发板像树莓派的GPIO引脚一样工作。
这也意味着这个任务里后面的程序只需要修改一行就可以运行。如果你需要自己对Arduino进行编程的话,要加载到Arduino的软件在新手包的anyio/arduino/firmware文件夹里。如果你和你的伙伴们想要在本书以外的项目里使用anyio软件包,你可以在我的github页面上找到最新版本。
配置驱动程序
设备连接到电脑之后,需要安装一个特殊的软件让电脑可以和设备进行通信——这个软件叫做设备驱动程序。你可能已经在自己的电脑上安装过设备驱动程序,在插上一台新的打印机或者其他设备的时候,这里我们也需要做同样的事情。
- 把USB连接线的一段接入Arduino,另一端插入电脑。
- 按照屏幕上的指示(不幸的是,这些知识在不同操作系统版本下也不一样)一步步安装驱动,这样才能在电脑上使用Arduino Pro Micro。
在Mac电脑上
你会看到一条消息弹出来,说发现了一个新的键盘。直接点红叉取消掉这个对话框。就是这样,在Mac电脑上的安装已经完成了。
在PC上
系统会让你下载一个驱动程序。但其实我们并不需要去下载,因为Windows已经包含了必要的驱动程序。不过Windows不太擅长识别未知的设备,所以我在新手包里准备了一个文件来帮助Windows正确识别。也就是anyio/arduino/firmware文件夹里的ProMicro.inf。打开这个目录,双击ProMicro.inf文件,点击“确定”。Windows现在应该能把这个设备识别为USB串口了。
david says
如果到这一步你的电脑还是不能识别设备,看一下这个sparkfun页面,照着上面的步骤做,这里的说明非常详细,而且会随着新版本操作系统的发布而更新。你可能也需要看一下SparkPang的产品页面,那里有更多对你有用的Pro Micro的教程。
找到串口号
Arduino以串口设备的形式连接到电脑上。这本书里不会详细解释什么是串口,不过我们需要确保anyio软件包使用了正确的端口,才能让GPIO扩展板运行起来。
我编写了一个小工具帮你找到正确的端口,包含在anyio软件包里了。图5-5展示了使用这个工具的一个例子,你可以看看它正常情况下应该是什么样子。
为了保证使用正确的端口:
- 打开IDLE,点击file->open来打开一个已经存在的python程序。
- 在MyAdventures目录里,打开findPort.py文件,它会被加载到python编辑器窗口。
- 在菜单里选择run->run module运行程序。屏幕上会显示操作步骤。
- 拔下Arduino那一边的USB插头,按回车键开始扫描。这一步我们要拔掉Arduino的USB插头让程序扫描电脑上所有可用的端口,除了我们马上要用的那一个,并建立一个列表。
- 接下来我们要接上设备,让程序再次扫描所有可用端口,用这个列表来检测刚刚被添加的新设备。重新插上USB插头,等几秒钟,然后再按回车键。
- 如果操作成功,你会看到一条包括端口名或端口号的消息,程序会问你是不是要记住这个端口。输入Y然后按回车。findPort.py程序(如图5-5)会生成一个名为findport.cache的文件用来记住Arduino的端口号。在之后使用GPIO功能的时候,程序就可以找到正确的Arduino端口。
提醒
如果你把其他的USB设备接入电脑,你可能会发现下次重启电脑之后或者接入Arduino开发板时,串口号就变了,程序也无法正常运行。如果出现这种情况,只要重新运行findPort.py程序,或者删除findport.cache文件然后重新运行程序再次扫描端口。
david says
编写一个在所有操作系统版本下都能正常运行的软件包是很难的,特别是操作系统在将来可能推出新版本。如果你在安装程序或者探测端口的时候碰到问题,请访问本书的配套网站看程序是否有新版本,或者可以到我的github页面上找到最新版本。
控制LED
在冒险任务1里,我们编写了一个helloMinecraftWorld.py程序,它会往聊天栏打印一条消息。学习控制电路的时候,我们可以编写一个等价于“hello world”的程序。不过不是在屏幕上显示消息,而是让一个LED闪亮起来。如果你在准备好系统之后能给电脑编程点亮一个LED,就可以确定所有东西都能正常工作,可以继续开始更大更有意思的项目了。
不过我们要点亮的是一个特别的LED,因为它会跟minecraft游戏连接起来。我们要扩展冒险任务2里试验过的魔法门垫。这次,我们的门垫要跟电路板象连接,站上去的时候LED会闪烁起来。不过,我们的电路不只可以和LED相连接,也可以和其他东西连接。想象一下,通过编程,当玩家走上门垫的时候可以发生的事情——可能打开真实卧室里的电灯或者窗帘,甚至更多!
技巧提示
在这个项目里,如果使用PC或者Mac电脑,就要使用anyio软件包。这个软件包已经包含在了新手包里,也可以从本章开头给出的链接下载。
用电脑点亮LED
首先要在面包板上把电路连接好。图5-6和5-7是连线方式的示意图。
- 找到LED上比较短的那一根引脚。这是LED的负极(阴极)。把这个引脚连接到面包板底部的0伏电源线。
- LED的另一只引脚比较长,这是正极(阳极)。把电阻器的一只引脚跟LED的长引脚插入面包板的同一行,另一只引脚接入面包板上半部的某一行。记住,我们需要电阻器来限制流过LED的电流大小。
- 为了测试LED,用一条线把面包板上半部的电阻器引脚和顶部的电源正极轨道连接起来。我们以后会去掉这跟线。
接下来的操作步骤,在树莓派和PC/Mac上有些不同,请阅读对应的部分。
树莓派:
- 如果你的工具包里有Pi-T-Cobbler的可粘贴标签,按照图5-8把它粘上。这样更容易找到正确的GPIO引脚。把Pi-T-Cobbler插到面包板上,接头放在面包板右边边缘。Push it into the right hand side of the breadboard so that it lines up with the holes on the far right hand edge of the breadboard。接头上一半的引脚位于面包板的上半部,另一半位于下半部。插紧一点放置掉下来。
- 把Pi-T-Cobbler的线缆接入树莓派。树莓派上的GPIO针脚和接头上的针孔是一一对应的,只能按一个方向插入。插好之后,检查一下接头上的所料接线片是背朝树莓派电路板边缘的,否则就是接反而,不能正常工作。图5-8是接好后的样子。
- 用一根导线把pi-t-cobbler上标有3V3的引脚和面包板顶部的正极电源轨连接起来。
- 用一个导线把pi-t-cobbler上标有0V的引脚和面包板底部的负极电源轨连接起来。
如果树莓派已经打开,LED就应该亮起来了,并且是由树莓派供电的。
david says
最后要做的事情是检查电脑是不是能点亮LED。在用python让LED闪烁起来之前,我们先要试试能不能用电脑的电源让它亮起来。
Arduino:
- 把Arduino插在面包板的右侧,让银色的USB接口突出来。你可能需要用点力才能把引脚插进去,不过用力的时候要均匀一点,不要把Arduino压断了。插好之后应该像图5-9那样。
- 连上电脑和Arduino之间的USB线。
- 用一根导线把面包板顶部的正极电源轨和Arduino上标有VCC(VCC是表示电源正极的专业术语,在Arduino上就是3.3V)的引脚连接起来。
- 用一根导线把面包板底部的负极电源轨和Arduino上标有GND(GND是电源0v的专业术语)的引脚连接起来。
如果Arduino已经打开,LED就应该亮起来了,它的电源供应来自电脑。
技巧提示
如果你的LED没亮,检查一下连接的方向对不对,或者换个方向试试能不能行。也可以重新检查一下面包板上面的连线对不对,从3.3V电源开始,顺着整个电路一直到0V,看看是不是每个连接都对。LED不亮的原因通常是方向插反了,或者LED的引脚没有插到面包板上正确的孔里,没有连成完整的电路。
让LED闪烁
现在我们已经验证过LED连接正确,并且能正常工作,最后要做的就是编写一个python程序让它闪烁起来:
- 启动IDLE,点击file->new file新建一个程序,并保存为testLED.py。
- 导入time模块,我们要用它在每次闪烁之间插入一个小的延迟。
导入控制GPIO的模块,定义一个常量来表示LED连接到的GPIO引脚号,按照下面说明进行:
树莓派:
import RPi.GPIO as GPIO LED = 15
Arduino:
import anyio.GPIO as GPIO LED = 15
设置GPIO引脚的编号模式。(你会看到代码里有BCM。对树莓派来说,这表示“Broadcom”。这是树莓派处理器的名字,这里的意思是告诉树莓派使用GPIO号码而不是开发板上的引脚号码。)接下来把我们要用的GPIO引脚设置为输出模式,这样才能用程序控制加在LED上的电压:
- 编写一个让LED闪烁一次的函数。这个函数要有一个参数,方便以后控制LED的闪烁速度。函数output()可以改变GPIO引脚上的电压,当参数为True的时候,电压为3.3V,参数为False时电压是0V。这样就可以让LED打开和关闭:
- 写一个游戏循环让LED闪烁,最后在程序结束时调用GPIO.cleanup()函数,把GPIO引脚置为安全状态。“深入代码”一节会解释try/finally的含义。
要让LED闪烁起来,必须把它连接到GPIO引脚上。按照下面步骤进行:
树莓派:
移动连接电阻器和3.3V电源轨的那根导线,把原来接在电源轨上的一边接到GPIO 15上(在Pi-T-Cobbler上标为G15)。
Arduino:
移动连接电阻器和3.3V电源轨的那根导线,把原来接在电源轨上的一边接到Arduino上的GPIO 15上。
提示
在本章的程序里,我们会使用import RPi.GPIO as GPIO或import anyio.GPIO as GPIO——这跟之前用过的 import mcpi.minecraft as minecraft是一样的。Python会把这个模块重新命名为as右边的名字,这在模块名字比较长的时候很有用。用这种方法,本章里的程序只需要修改一两行就可以在Arduino和树莓派两种平台上运行。这是python的一个很有用的功能。
提醒
Arduino开发板上自带了一些LED,黄色LED亮起来表示Arduino正在从USB接口接受命令。你会看到它以两倍于面包板上LED的速度闪烁,因为每个让面板板上LED亮起或者关闭的命令都会让黄色LED闪烁一次。不要被它迷惑,这是正常的!
运行GPIO程序
最后该运行我们的程序了,看LED是不是会闪烁起来。
PC/Mac:
我们可以像以前一样直接从IDLE运行程序。Arduino开发板通过USB连接到PC或者Mac,我们有足够的权限来使用这个设备。
树莓派:
在树莓派上运行程序稍微复杂一点。虽然还是可以在IDLE里编辑程序,但是运行使用GPIO的程序和本书中的其他程序不一样。“深入代码”一节会解释为什么我们要做这些额外的操作。
- 从桌面菜单里打开LXTerminal程序。这会打开一个命令提示符窗口,用来给树莓派输入命令。
输入下面命令改变当前目录到MyAdventures:
cd MyAdventures
用sudo命令运行python程序:
sudo python testLED.py
LED闪起来了吗?这看起来微不足道,不过到这里我们已经迈出了一大步。我们现在已经打破了电脑的边界,可以用它来控制电路了。
david says
这里可能会有一条警告“Channel already in use”。别担心,这是正常的。稍后我们会学到如何用GPIO.cleanup()来避免这条警告。
接下来要做的是把这个程序跟minecraft世界联系起来,这也是这个实验的最后一个任务。
提示
还记得我说过编程让LED闪烁就是电路版的“Hello world”吗?当你把电脑跟电路连接起来的时候,最好先让这个例子运行起来,然后再去做一些更复杂的东西。如果LED没有闪烁,仔细检查你的连线,确保LED和GPIO之间的连线都插在了面包板上正确的针孔里。我们之前已经测试过用电脑的3.3V电源给LED供电是可以亮起来的,所以如果它不能闪烁,要不就是程序写错了,要不就是LED和GPIO之间的导线连得不对。
深入代码
在刚才的程序里,我们使用了两个技巧,需要详细解释一下。
首先,try/finally/GPIO.cleanup()是什么意思?
为了防止每次运行程序时都出现前面提到的警告,在程序结束之前一定要调用GPIO.cleanup()。这会把所有的GPIO引脚设置为输入,并关闭GPIO电路。“设置为输入”的意思是这些引脚将不再主动控制电路。如果在插拔的时候不小心把一个输出引脚和另一个引脚连接在一起,可能会造成短路破坏电路。为了防止这种情况,一定要养成在程序里调用GPIO.cleanup()的好习惯,这样才能避免意外的短路对电路造成破坏。
不过有个问题:因为我们在程序里用了while True:,在python程序里,这表示程序进入了一个无限循环。退出程序的唯一方法是按Ctrl+C或者从IDLE菜单里停止程序。不过,假如用这些方法,程序就会立刻停止。
别担心——我们有办法解决这个问题,这需要用到try/finally,也被称作异常处理。这本书里不会深入去讲关于异常处理的知识,不过在涉及到GPIO的时候,我们不得不使用这个办法。一般来讲,按下Ctrl+C或者从IDLE菜单停止程序时,python会产生一个叫做KeyboardInterrupt的异常,然后程序就会停止运行。try/finally是一种可以让python程序检测到程序停止运行的编程技巧。在finally语句之后,可以加入任何python代码以便在程序结束前进行清理工作。所以,当按下Ctrl+C或者从IDLE菜单停止程序的时候,程序会跳到finally:后面的代码块,执行这些代码然后退出。这保证了GPIO.cleanup()总是会被执行,当程序退出时,GPIO引脚总是会被置为安全状态。
这本书里不会再深入去讲解异常了,不过你可以在这里了解更多这方面的知识。
第二,在树莓派上执行的sudo命令是什么意思?为什么要从LXTerminal启动GPIO程序呢?
树莓派上所有的硬件都是受保护的,我们登录用的pi用户通常是不能访问的,除非有超级用户权限。sudo的意思是“切换用户然后执行(substitue user and do)”,这通常会把当前用户从pi切换到root(也就是超级用户)然后运行testLED.py程序。这样我们的程序就可以访问受保护的硬件。在树莓派上如果不按这种方式运行GPIO程序,就会出现错误。
在写这本书的时候,我试着寻找一个关于sudo的清楚的解释。有趣的是,Google搜索最终把我带到了我自己的博客网页,看起来这个网页很受欢迎!你可以在这里找到更多关于sudo和它的用法的知识。
带LED的神奇门垫程序
LED实验里要做的最后一件事是把它跟Minecraft游戏连接起来。幸运的是,最后这一步很简单,需要用到的所有东西我们都已经学过了。
- 在IDLE菜单里选择file->save as把testLED.py保存为另外一个文件,名为welcomeLED.py。
- 在文件的最上面添加导入minecraft模块的语句,并连接到minecraft游戏。
- 在这几行的下面,定义几个常量来表示门垫的座标。我们需要确定门垫在minecraft世界中的位置,然后确定这几个常量的值。在树莓派里,我们可以在minecraft窗口的左上角看到座标。在PC/Mac电脑上,我们需要按下F3键来查看座标:
- 接下来,在选好的位置创建一个羊毛方块,这就是我们的门垫——跟冒险任务2里的一样:
- 按照下面方式修改游戏循环。要特别注意缩进。这段代码会循环读取玩家的位置,判断他是否站在门垫上。如果是,就会让LED闪烁来欢迎你回家。
按照前面给出的方法运行程序,看看当你站在门垫上的时候,LED是不是会闪烁起来表示欢迎。
太神奇了!我们现在已经掌握了打破minecraft的虚拟沙盒世界,把游戏和现实连接起来所需要的全部秘诀。如果可以写程序让LED闪烁,就可以进一步控制任意数量的电子设备——只有想象力和行动力能限制你!
挑战
找一些其他颜色的LED,把它们连接到其他的GPIO引脚上。用一个蓝色LED,并修改程序,用getBlock()判断玩家是不是正站在水面上,如果是,让蓝色LED亮起来。用一个绿色LED,当玩家站在草地上的时候让它亮起来。试试看用这种方法(当minecraft世界中发生某种情况时打开LED)你能作出多少不同的东西?
使用7段显示器
这个冒险任务的下一个项目是使用一种很常见的LED显示器,在minecraft世界里发生某种情况时,显示数字或者其他符号。我们之后在这本书的最终项目里还会用到这种显示器。在把显示器和minecraft联系起来之前,我们需要先把它连接好,确保能正常工作。完成这些之后,再把它跟minecraft游戏连接起来就很简单了,就跟LED一样。
提示
在这个项目里,如果使用PC或Mac,需要使用anyio软件包。这个软件包已经包含在了新手包里,同时也可以从本章开头给出的地址下载。
7段显示器
如果你在家里转转,或者走进一加商店,你会看到成百上千的设备都在使用7段显示器,电子表、计时器、微波炉、CD播放器、甚至是中央供暖设备的控制器,都使用了7段显示器。图5-10是7段显示器的独特表现形式,以及其内部连接方式。
所有的7段显示器内部都有多个不同的LED。最常用的一种,也是我们在接下来的项目中要使用的,实际上内部有8个LED,但是其中一个是在显示器的下角用来做小数点的。只有7个LED是专门用来显示符号的,它们像图5-10所示的那样组成数字8的形状。
关于7段显示器,有两件事情我们必须先了解:
- 这个显示器是由8个LED组成的,如果能写程序控制一个LED的开关,就可以很容易的写程序驱动这个显示器。它只是有8个GPIO连接而已。
- 使用这种7段的形式,通过LED的不同组合可以显示很多的符号。用这些段足够显示0到9之间的任意数字了。
在图5-10里,除了7段显示器的内部连接,我们还可以看到它的引脚和各个LED之间的对应关系。我们可以看到所有LED的正极(阳极)都连接到了同一个引脚,这个引脚我们要把它连接到面包板上的3.3v电源轨。二极管符号上的箭头显示了电流流动的方向,所以它是从正极指向负极的。
david says
标签ABCDEFG是工业界用来表示7段显示器的约定方式。如果你看过很多显示器的话,你会发现这些“段”都是稍微向右倾斜的。这是多数生产商采用的一种让它们看起来更美观的设计方案。
提醒
你可以买到很多不同幸好的7段显示器,其中很多的连线方式都不一样。有些是共阴极的(意思是所有LED的阴极连在一起),有些是共阳极的(意思是所有LED的阳极连在一起)。还有一些7段显示模块每个LED都有不同的引脚。这个项目里使用的是www.skpang.co.uk提供的共阳极7段显示器,如果你买的是不同型号,在接线之前要仔细看它的引脚说明。如果你使用的是共阴极7段显示器,只需要修改程序中用到ON常量的地方,我在这些地方都加了注释。
连接7段显示器
现在我们可以把7段显示器连接到面包板并检查它是不是能正常工作,按照步骤进行:
- 把7段显示器插在面包板上,让显示器的上半部和面包板的上半部重合,下半部和面包板下半部重合。上半部分和下半部分各有5个引脚,每个引脚跟面包板的一个孔对齐。
- 从显示器上半部分中间的引脚(共阳极)连接一条线到面包板顶部的3.3v电源轨。(如果使用的是共阴极显示器,就需要从下半部分中间那根引脚连一根线到面包板底部的0v电源轨。)
- 因为显示器里面用的是LED,我们要像之前一样加一个电阻器。因为这里有8个LED,所以需要8个电阻器。拿8个330欧电阻器(彩条的颜色分别是橙色、橙色、棕色),把每个电阻器的两边引脚都折弯,放在显示器的一个引脚和面包板上的一个空闲孔之间。图5-12里是正确的连接方式。再看一下图5-4,复习一下面包板上的条带是怎么连接的,别把所有的电阻器都短路了。
- 现在可以测试显示器了。从面包板底部的0v电源轨接一根线,依次连到各个电阻器的空闲引脚(没有跟显示器连接的那一边)上。每连接一个电阻器的引脚,就会有一个不同的段亮起来。比较亮起来的段和图5-10中的示意图,也是我自己在这个项目里用的显示器,看看你的显示器是不是跟我一样。如果不一样,记下每个段和电阻器的对应关系,之后会用到。(见图5-11。)
测试完显示器,确认它能正常工作之后,下一步就是把它连接到GPIO上,这样才能用python程序来控制显示器里的每个LED。从每个电阻器的空闲引脚连接一条导线到一个GPIO引脚——如果使用树莓派,就按图5-12的方式连接;如果使用Arduino,就按图5-13的方式连接。如果在之前的测试过程中发现你用的显示器跟我的不一样,用那时候记下来的信息把显示器的每个引脚连接到正确的GPIO上。不这样的话,后面运行程序的时候就会出现一些很奇怪的显示。
编写python程序驱动7段显示器
我们已经测试过7段显示器,并把它连接到了7个GPIO上,接下来可以编写python程序来控制它了:
- 点击file->new file新建一个python程序,保存为testDisplay.py。
导入所有需要的模块,并生命一组常量来表示GPIO引脚:
树莓派:
import RPi.GPIO as GPIO LED_PINS = [10,22,25,8,7,9,11,15] # order important
Arduino:
import anyio.GPIO as GPIO LED_PINS = [7,6,14,16,10,8,9,15] # order important
设置正确的GPIO模式:
- 选择显示的类型(我是用的是共阳极显示器):
- 编写一个循环设置8个引脚为输出:
- 显示器上的每个LED只能是开或关两种状态之一。用7段显示器显示符号的一个好方法是,把7个True或者False保存在一个列表里,列表里的每个下标都代表显示器里的一个LED。还记得在冒险任务4里用过的列表和下表吗?这里也是一样的。下面这个列表会打开ABCDEFG几个段(因为值为True),不过小数点会关闭,因为最后一个元素的值是False。列表里的下标[0]表示段A,下标[1]表示段B,以此类推。
- 编写一个循环打开指定模式里的对应的引脚:
- 现在,要让程序等待任意键按下然后结束;不然程序一结束,所有的LED都会关闭,什么也看不到了。使用raw_input()函数会让程序等待用户输入按下键盘上的回车键,然后才会接着执行下一行代码:
最后,让程序清理GPIO状态,然后退出:
GPIO.cleanup()
运行程序,看看有什么结果。记得在树莓派上要从LXTerminal窗口输入sudo python testDisplay.py来运行程序。
挑战
试着推算出表示数字0-9的模式列表。记住列表里的True/False值一次对应A、B、C、D、E、F、G、DP。你可以在7段显示器上显示多少种不同的字母?你可以在这个维基百科页面上找到一些有用的7段显示器显示模式。
使用python模块控制显示器
你也许已经发现7段显示器可以用来显示很多种不同的模式。为了让显示这些模式变得更简单,我写了一个叫做seg7.py的程序,包含在新手包的anyio目录里。你可以直接使用或者按照自己的需要修改这个程序并添加到自己的游戏和程序里。把这个程序包含到现有的程序里是很简单的,按照下面步骤进行:
- 点击file->new file新建一个程序,保存为testDisplay2.py。
- 导入显示模块,以及用来加入延迟的time模块:
- 把testDispaly.py里从ON=False一行开始的所有内容都拷贝到新文件里:
- 之后,设置显示模块,让它可以访问GPIO引脚,并把显示器所有段对应的引脚号作为一个列表传递给它:
- 编写一个游戏循环从0数到9。这么做是为了让程序可以一直运行下去,如果某些段不能正常工作,你可以去调整一下连线,而不用一直重新运行程序。
保存并运行程序。看看会发生什么?显示器会一直重复显示从0到9。记得在树莓派上需要从LXTerminal窗口用命令sudo python testDisplay2.py来运行程序。
提醒
上面程序里的time.sleep(0.5),可以替换成更长的延迟(比如2秒),或者raw_input(),这样显示的内容在你调整连线的时候可以保持不动。
挑战
打开MyAdventures/anyio文件夹里的seg7.py程序,按照文件里的说明添加一些新符号。试着把你在前一个挑战里设计的字母添加到这个模块里,看看你能加多少。如果一次显示一个字母的话,能显示哪些单词呢?能拼出你的名字吗?还缺哪些字母表里的字母?
引爆器
这个冒险任务里的最后一个项目里,我们要制造一个红色引爆按钮。按下按钮时,7段显示器上会开始倒计时,让玩家有机会逃离爆炸,然后在刚才玩家站的地方会出现一个巨大的弹坑。这对我们的工具箱也是一种很有用的补充,可以迅速清理出一些空间用来建造东西。这个项目将会引入另一种类型的GPIO,也就是输入,可以检测到按钮按下——我们也会把7段显示器充分利用起来。
提示
在这个项目里,如果使用PC或者Mac,就要使用anyio软件包。这个软件包已经包含在了新手包里。
连接按钮
这个项目的第一步是连接一个按钮用来启动引爆装置。选一个大的红色按钮,这样看起来更让人兴奋。
我们要用的是一个非锁定、按下触发的按钮。意思是正常情况下电路是不通的——只有按下按钮的时候才会通。不过按钮不会保持按下状态,手拿起来之后电路就会再次断开。
图5-14是树莓派的电路示意图,图5-15是Arduino的电路示意图。你可以按照示意图来连接电路,也可以按照下面的步骤进行。
- 把按钮插入面包板上的某个空闲位置。我用的按钮上有4个引脚(图5-16),刚好能装在面包板的中间。按下按钮会让左侧和右侧的引脚连起来,只要像图5-14和5-15那样把按钮上下的引脚都插进面包板。
- 我们需要一个电阻器来把按钮输入和3.3V引脚连接起来。如果不用电阻器,按钮就会产生错误的信号,引爆器会一直不停的引爆!(“深入电路”一节会详细解释为什么要用这个电阻器。)把一个10千欧电阻(彩带的颜色分别是:棕色、黑色、橙色)的一只引脚跟按钮的左侧引脚连起来,另一只引脚接到面包板顶部的3.3v电源轨。
- 用一根导线把电阻器和按钮之间的连接点,和GPIO引脚4连起来。
- 用一根导线把按钮右下角的引脚跟面包板底部的0v电源轨连接起来。“深入电路”一节会详细解释这个电路的工作原理,所有按钮通常都是用这种方式连接到电脑的。图5-16是一个连接到GPIO的按钮。
提醒
按钮有很多种不同的类型。如果你用的按钮类型跟我的一样,你会发现按钮的四个引脚有点弯曲,一遍适应印刷电路板,方便焊接。把按钮插进面包板的时候要小心别把引脚弄断了。用力要均匀稳固,就能插进去。如果有小钳子,可以用它把引脚弄平,这样更容易插进面包板。
深入电路
连接好按钮之后,我们加上了一个电阻器。这个叫做上拉电阻器,因为它把按钮这个引脚的电压拉升到3.3V。
当按钮没有按下的时候(电路也没有连通),连接GPIO引脚和这一点的导线上电压是3.3V,GPIO引脚会把这个电压当作“1”。按下按钮之后,按钮的内部机制把左右两侧的引脚连通,GPIO被连接到0v电源轨,电压降到0v。在这种情况下,GPIO引脚会被当作数字“0”。这个电阻器的阻值很高(10k欧姆,也就是10,000欧姆),不然按钮就会把3.3v电源轨和0v电源轨短路,会导致电脑重启。千万不要这样做,因为有可能会损坏你的电脑。10K是工程师表示10,000欧姆的简写形式。
编写引爆器程序
我们已经连好了按钮,最后一步是编写python程序。程序会在每个游戏循环里监控按钮的状态,如果检测到GPIO引脚上是“0”(也就是说,按钮按下),程序就会在7段显示器上从5倒数到0,然后就在minecraft世界里炸出一个大坑。
- 点击file->new file新建一个程序,保存为detonator.py。
- 导入需要的模块:
- 配置GPIO:
- 设置连接按钮的GPIO为输入,并配置显示用的GPIO引脚:
- 连接到minecraft游戏:
- 编写一个函数往炸弹要爆炸的位置丢一个TNT方块,倒数到0,然后在TNT方块的位置炸出一个大坑。下面的代码会把TNT方块放在玩家旁边一点的位置,这样就不会正好落在玩家头上。注意,弹坑的尺寸是20个方块大小(玩家的左右两边各10个方块),设置尺寸是通过setBlocks()函数里的计算完成的:
- 编写主游戏循环,等待按钮按下,然后引爆炸弹。记住当按钮按下的时候,是连接到0v的,所以我们要把按钮的GPIO引脚个False进行比较来检测按钮是否被按下:
保存并运行程序。记住在树莓派上,需要从LXTerminal窗口执行命令sudo python detonator.py来运行程序。
走到minecraft里的某个位置,按下红色按钮——然后赶紧逃命!图5-17展示了爆炸的效果——一个巨大的弹坑。
david says
弹坑的尺寸是用setBlocks()函数里的数字来设置的。你觉得这个方式好吗?如果想把弹坑的尺寸增加一倍怎么办,需要修改多少代码才能实现?你有没有觉得我这里偷懒了呢?为什么不试着自己改进我的程序呢,让修改弹坑尺寸更容易一点?
挑战
要让引爆器更刺激一点,试试加入像冒险任务2里那样的地理围栏代码来检测玩家是不是在爆炸范围之内。当炸弹引爆的时候,如果玩家还在爆炸半径之内,就用mc.player.setTilePos()函数把玩家弹到空中。
挑战
在电路里添加三个按钮,方法跟添加第一个按钮一样。编写python代码让这些按钮触发一些其他的事情,比如想minecraft聊天栏里发送一条消息,把玩家传送到一个秘密地点,在玩家站的位置建造不同形状的方块,甚至在建造一整座房子等等。下面这些GPIO引脚可以放心的用来连接三个按钮。
button Raspberry Pi Arduino BUTTON2 14 5 BUTTON3 23 2 BUTTON4 24 3
david says
完成这个冒险任务之后留着电路不要动。接下来在冒险任务9的最终项目里还会用到同样的电路,我也会在配套网站上下载的额外章节里再次使用这个电路。
更多关于电路的冒险
在这个冒险任务里,我们把minecraft世界和现实世界联系了起来,通过感知和控制真实世界中的事物,我们把自己的得以窥探物理计算的精彩世界。我们用新学到的知识让LED闪烁,在7段显示器上显示符号,感知按钮按下。最重要的是,我们逃离了minecraft沙盒世界的限制。用这些新学到的知识,我们可以自己制造出令人惊叹的游戏控制器和显示设备。
- 这本书里没有太多的篇幅来讲解使用电路制作的游戏,不过我一开始琢磨设计游戏的点子,就会有数不清的新点子冒出来。额外章节里的minecraft电梯是其中一个,我把它放到配套网站上以便读者们可以自己尝试做。
- 我们在树莓派俱乐部的一个孩子想到了一个很妙的点子,用一块卡片制作一个冒险地图
- 有人想到了一个把电子加速度计连接到电脑的方法,用它可以感知真实手臂的运动并翻译成机器手臂的运动。看一下这个视频。看看你能不能找到办法把加速度计连接到自己的电脑上,并通过移动手臂来控制minecraft游戏。如果成功了,不如去一个本地的创客聚会上展示一下,让别人见识一下miencraft电子电路的精彩世界。
下一个冒险任务
在冒险任务6里,我们会学习从文件中读取数据来自动建造大型的、复杂的minecraft建筑,比如迷宫。我们还会用自己新学到的技巧来建造一个巨大的3D复制机用来在minecraft世界里复制大的物体。树木以后就不一定是老老实实的扎根地下了!