跳轉到內容

維基少年:樹莓派/樹莓派樂高®交通燈

來自華夏公益教科書,開放世界開放書籍

教程作者:安德魯·奧克利
公有領域,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?
華夏公益教科書