跳转到内容

维基少年:树莓派/树莓派乐高®交通灯

来自维基教科书,开放世界开放书籍

教程作者:安德鲁·奥克利
公有领域,2015年9月26日
www.cotswoldjam.org

LEGO®是乐高集团公司的商标,并不赞助、授权或认可本教程或Cotswold Raspberry Jam。

本教程将向你展示如何基于LED(灯)和树莓派计算机构建一套交通灯。这些灯可以放置在乐高®技术积木中,并与其他乐高®模型一起使用。

Things that appear on the screen or need to be typed in are written like this.

在每行代码的末尾,你通常需要按 ↵ Enter 键。

你的导师应该已经为你准备好了树莓派。如果没有,请参见文末的“准备工作”部分。

电子元件

[编辑 | 编辑源代码]

发光二极管(LED)有一个短腿和一个长腿。如果你摸摸边缘,你会发现一个平坦的边缘。短腿和平坦的边缘始终连接到负极(接地)。我们使用5mm LED,因为它们可以插入乐高®技术的孔中。

电阻器可以以任何方式连接。较低值(较低欧姆)的电阻器会允许更多的电流通过,使LED更亮;较高值的电阻器会允许更少的电流通过,使LED更暗。我们使用一个270欧姆的电阻器,但220-470欧姆之间的任何电阻器都可以正常工作。我们将使用一个连接到地线的电阻器来覆盖所有3个LED。

这三块乐高®积木可以组合成一个交通灯,5mm LED可以插入技术积木的孔中。

这些积木的零件编号 – 可以在eBay或Bricklink.com等网站上购买二手 – 为

将LED推入技术积木,使每个LED的短腿位于底部。

你需要将短腿连接到单个电阻器,然后连接到树莓派的地线引脚之一。你的导师可能已经做了一个特殊的“猪尾巴”电缆来做到这一点,或者你可以使用面包板。

接地(负极)线

[编辑 | 编辑源代码]

猪尾巴电缆
你的导师可能已经使用DuPont压接器制作了这条电缆。

它在一侧有三个母头,插入LED的短腿,中间有一个电阻器,另一侧有一个母头,插入树莓派的9号引脚(接地)。一小段透明的胶带包裹在电阻器周围,以固定它。

面包板

如果你没有专门制作的猪尾巴电缆,你可以使用面包板来连接三个LED的短腿到一个电阻器和接地。你需要四根公对母跳线,加上电阻器。

不要担心跳线的颜色。它们不必与LED的颜色匹配。本文档的作者严重色盲,所以颜色无论如何都是随机的。

面包板顶部的三根跳线连接到LED的短腿。面包板底部的单根跳线连接到树莓派的接地(9号引脚)。

信号(正极)线

[编辑 | 编辑源代码]

连接好电阻器和接地线到LED的短腿后,你可以使用一根母对母跳线将长腿连接到树莓派的1号引脚(3.3伏直流)(假设树莓派已通电)来测试任何LED。

但是,我们不希望灯一直亮着;我们需要通过程序控制它们。测试完灯后,断开1号引脚。

为了通过程序控制LED,使用母对母跳线将LED的长腿(正极)连接到树莓派的以下引脚:

  • 11号引脚 - 红色
  • 13号引脚 - 黄色
  • 15号引脚 - 绿色

启动你的树莓派,登录并进入桌面。如果你需要登录,默认用户名是 `pi`,密码是 `raspberry`。如果桌面仍然没有出现,输入 `startx` 并按下 ↵ Enter 键。

从菜单中选择 Programming – Python 3。然后使用 File, New Window 创建一个新的程序。

输入以下程序,或者你也可以使用 File, Open 打开 python/traffic 文件夹中的 traffic1.py 程序。

import RPi.GPIO as GPIO, time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

red=11
yellow=13
green=15

GPIO.setup(red, GPIO.OUT)
GPIO.setup(yellow, GPIO.OUT)
GPIO.setup(green, GPIO.OUT)

使用 File, Save 保存该程序为 `traffic1.py`。以下是该程序的功能

import RPi.GPIO as GPIO, time

此命令告诉树莓派关于其 GPIO 引脚的信息,因此它可以打开和关闭 LED,并且关于时间,因此我们可以告诉它在每种颜色之间等待几秒钟。

GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

在这里,我们告诉计算机按板子上排列的顺序使用引脚编号来调用引脚(有一种称为 BCM 的替代编号方式)。接下来,我们告诉它不要在 GPIO 引脚已经被使用时发出警告。

red=11
yellow=13
green=15

现在,我们告诉树莓派哪些引脚用于哪种颜色的 LED。请注意,我们不必说明我们使用引脚 9 用于接地;这并不重要。

GPIO.setup(red, GPIO.OUT)
GPIO.setup(yellow, GPIO.OUT)
GPIO.setup(green, GPIO.OUT)

最后,我们告诉树莓派准备红色、黄色和绿色引脚用于输出。如果我们正在获取输入,例如读取开关,那么这段代码将看起来不同。

程序的这部分只是做好一切准备。它实际上并没有打开任何 LED。我们将在下一步中进行操作。

使用 File, Save As 保存程序为 `traffic1.py`。不用担心它告诉你该程序已经存在——无论如何保存它。

点亮一个 LED

[编辑 | 编辑源代码]

让我们从点亮黄色 LED 开始。在程序底部添加以下几行

GPIO.output(yellow, GPIO.HIGH)
time.sleep(2)
GPIO.output(yellow, GPIO.LOW)

HIGH 打开灯光。LOW 关闭灯光。

保存程序为 `traffic2.py`。

现在保持 Python 窗口打开,并通过转到主桌面菜单 - 附件 - 终端启动一个终端会话。你应该会看到一个黑色的窗口打开。

在终端中,输入

cd python/traffic
sudo python traffic2.py

你应该会看到黄色 LED 亮起两秒钟,然后 LED 会熄灭,程序将结束。你可以通过再次输入 `sudo python traffic2.py` 来重复程序。

尝试修改程序以点亮红色或绿色 LED。

反复闪烁一个 LED

[编辑 | 编辑源代码]

现在让我们修改程序,使最后几行显示为

while (True):
  GPIO.output(yellow, GPIO.HIGH)
  time.sleep(2)
  GPIO.output(yellow, GPIO.LOW)
  time.sleep(2)

保存该程序为 `traffic3.py`。回到黑色终端窗口并使用以下命令运行它

sudo python traffic3.py

黄色 LED 应该每 2 秒闪烁一次。

按住 CTRL 键并轻触 C 键退出程序。这可能会使黄色灯光保持亮起!不用担心。

完整的序列

[编辑 | 编辑源代码]

英国交通灯的完整序列是

  • 红色(停止)——持续很长时间
  • 红黄一起(准备行驶)——持续很短时间
  • 绿色(行驶)——持续很长时间
  • 单独的黄色(准备停止)——持续很短时间

让我们修改程序以执行完整的序列

while (True):
  GPIO.output(red, GPIO.HIGH)
  time.sleep(5)
  
  GPIO.output(yellow, GPIO.HIGH)
  time.sleep(2)
  
  GPIO.output(red, GPIO.LOW)
  GPIO.output(yellow, GPIO.LOW)
  GPIO.output(green, GPIO.HIGH)
  time.sleep(5)
  
  GPIO.output(green, GPIO.LOW)
  
  GPIO.output(yellow, GPIO.HIGH)
  time.sleep(2)
  
  GPIO.output(yellow, GPIO.LOW)

就是这样!保存该程序为 `traffic4.py`。回到终端窗口并使用以下命令运行它

sudo python traffic4.py

按住 CTRL 键并轻触 C 键退出程序。

你可以在停止程序后使用 alloff.py 程序来关闭所有灯光。此外,还有 `traffic5.py` 程序,它使用一些高级技术在程序停止时关闭灯光。

进一步的冒险

[编辑 | 编辑源代码]

以下是一些你可以做的其他事情的想法

从一台树莓派运行两组灯光

[编辑 | 编辑源代码]

你可以使用引脚 12、16 和 18(加上引脚 14 用于接地)来控制另一组灯光。

对于 T 形路口,你需要 3 组灯光。对于十字路口,你需要 4 组

[编辑 | 编辑源代码]

在 Model B+ 或 Pi 2 上,你可以使用引脚 36、38 和 40(加上引脚 34 用于接地)来控制第三组灯光,或者你可以使用两台树莓派。

如果你有多台树莓派,如何同步灯光?两台树莓派如何相互通信?

你如何检测到一辆玩具汽车正在等红绿灯?

[编辑 | 编辑源代码]

如果是一辆塑料 LEGO® 汽车或一辆金属玩具汽车,你的策略是否有效,或者两者都行?汽车的重量是否重要?

如果是自行车或马怎么办?现实世界中的交通灯如何检测自行车和马——它们有其他策略吗,或者它们忽略了这个问题?

你如何在你打开树莓派时自动运行你的程序?

[编辑 | 编辑源代码]

尝试搜索有关 `crontab @reboot` 命令的信息:https://www.adminschoice.com/crontab-quick-reference

本教程的文件可以在以下位置找到:http://www.cotswoldjam.org/downloads/2015-09/

请在 home/pi 目录下创建一个 `python` 文件夹,然后将文件解压缩到该 `python` 文件夹中。这可以在 LXTerminal 中完成

mkdir python
unzip traffic.zip

本教程的原始 PDF 文件位于 Wikimedia Commons:Cjam-traffic-light-tutorial.pdf

alloff.py

[编辑 | 编辑源代码]
#!/usr/bin/env python

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

red=11
yellow=13
green=15

GPIO.setup(red, GPIO.OUT)
GPIO.setup(yellow, GPIO.OUT)
GPIO.setup(green, GPIO.OUT)

GPIO.output(red, GPIO.LOW)
GPIO.output(yellow, GPIO.LOW)
GPIO.output(green, GPIO.LOW)

traffic1.py

[编辑 | 编辑源代码]
import RPi.GPIO as GPIO, time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

red=11
yellow=13
green=15

GPIO.setup(red, GPIO.OUT)
GPIO.setup(yellow, GPIO.OUT)
GPIO.setup(green, GPIO.OUT)

traffic2.py

[编辑 | 编辑源代码]
import RPi.GPIO as GPIO, time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

red=11
yellow=13
green=15

GPIO.setup(red, GPIO.OUT)
GPIO.setup(yellow, GPIO.OUT)
GPIO.setup(green, GPIO.OUT)

GPIO.output(yellow, GPIO.HIGH)
time.sleep(2)
GPIO.output(yellow, GPIO.LOW)

traffic3.py

[编辑 | 编辑源代码]
import RPi.GPIO as GPIO, time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

red=11
yellow=13
green=15

GPIO.setup(red, GPIO.OUT)
GPIO.setup(yellow, GPIO.OUT)
GPIO.setup(green, GPIO.OUT)

while (True):

  GPIO.output(yellow, GPIO.HIGH)
  time.sleep(2)
  GPIO.output(yellow, GPIO.LOW)
  time.sleep(2)

traffic4.py

[编辑 | 编辑源代码]
import RPi.GPIO as GPIO, time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

red=11
yellow=13
green=15

GPIO.setup(red, GPIO.OUT)
GPIO.setup(yellow, GPIO.OUT)
GPIO.setup(green, GPIO.OUT)

while (True):

  GPIO.output(red, GPIO.HIGH)
  time.sleep(5)

  GPIO.output(yellow, GPIO.HIGH)
  time.sleep(2)

  GPIO.output(red, GPIO.LOW)
  GPIO.output(yellow, GPIO.LOW)
  GPIO.output(green, GPIO.HIGH)
  time.sleep(5)

  GPIO.output(green, GPIO.LOW)
  GPIO.output(yellow, GPIO.HIGH)
  time.sleep(2)

  GPIO.output(yellow, GPIO.LOW)

traffic5.py

[编辑 | 编辑源代码]
#!/usr/bin/env python
# GPIO traffic lights by Andrew Oakley for Cotswold Raspberry Jam
# http://www.cotswoldjam.org September 2015 Public Domain

# Start by reading the library about GPIO pins and timing
import RPi.GPIO as GPIO, time, signal, sys

# Set up the GPIO pins
# We're using board numbering as it works for all Pis
# including original Rev.1 boards
GPIO.setmode(GPIO.BOARD)

# Turn off warnings, notably if the pins are already set
GPIO.setwarnings(False)

# Turn off lights if process is killed
def signal_term_handler(signal, frame):
  GPIO.output(red, GPIO.LOW)
  GPIO.output(yellow, GPIO.LOW)
  GPIO.output(green, GPIO.LOW)
  print 'got SIGTERM'
  sys.exit(0)
signal.signal(signal.SIGTERM, signal_term_handler)

# Which colours are on which pins?
# You can use pin 9 for ground
# Attach ground to the shortest leg of the LED
red=11
yellow=13
green=15

# Set up the pins for output
GPIO.setup(red, GPIO.OUT)
GPIO.setup(yellow, GPIO.OUT)
GPIO.setup(green, GPIO.OUT)

# We use TRY and EXCEPT to allow us to
# turn the lights off after stopping the
# program using CTRL-C, or during shutdown
try:

  # Loop round forever, until stopped by CTRL-C
  while (True):

    # Start with Red
    GPIO.output(red, GPIO.HIGH)
    time.sleep(5)

    # Leave red on, and turn yellow on too
    # Red & yellow together is mostly a British thing
    # Countries like France and the USA don't have it
    # they go straight from red to green
    GPIO.output(yellow, GPIO.HIGH)
    time.sleep(2)

    # Turn off red and yellow
    GPIO.output(red, GPIO.LOW)
    GPIO.output(yellow, GPIO.LOW)
    # Turn on green
    GPIO.output(green, GPIO.HIGH)
    time.sleep(5)

    # Turn off green
    GPIO.output(green, GPIO.LOW)
    # Turn on yellow
    GPIO.output(yellow, GPIO.HIGH)
    time.sleep(2)
    GPIO.output(yellow, GPIO.LOW)

# If we have pressed CTRL-C, or if the computer
# is being shut down, then turn all lights off
except (KeyboardInterrupt, SystemExit):
  GPIO.output(red, GPIO.LOW)
  GPIO.output(yellow, GPIO.LOW)
  GPIO.output(green, GPIO.LOW)
  # Report the reason for stopping
  raise

# Now have a think about how you might expand this program
# A T-junction needs 3 sets of lights
# A crossroads needs 4 sets
# Could you wire all sets of lights from one Raspberry Pi?
# What about a left turn filter?
# At night some part-time lights just flash yellow
# If you had two Raspberry Pis, how could they communicate
# so that they could synchronise their lights?
华夏公益教科书