跳转到内容

维基少年:树莓派/树莓派 Python GPIO Zero 距离传感器

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

教程作者:乔纳森·蒂格 - 公共领域
2017 年 1 月 28 日 - www.cotswoldjam.org

本教程将介绍使用流行的 HC-SR04 超声波距离传感器、树莓派和gpiozero库来测量距离。

你的包中包含以下组件

  • ×4 个 M-F 跳线(公针到母座)
  • ×1 个 R1 680Ω(蓝灰棕)电阻
  • ×1 个 R2 470Ω(黄紫棕)电阻
  • ×1 个迷你面包板
  • ×1 个 HC-SR04 超声波传感器

使用面包板

[编辑 | 编辑源代码]

面包板用于原型设计和测试电子元件,无需焊接。

每个孔都使用一种符号系统进行标识,该系统使用水平方向上的数字和垂直方向上的字母来标识面包板上的孔。

使用树莓派的 GPIO 引脚

[编辑 | 编辑源代码]

树莓派有两种方法对通用输入输出 (GPIO) 引脚进行标记

  • 板号 – 从左下角开始,从 1 开始,向上和向右排列,一直到 40。
  • BCM 号码(博通号码) – 是树莓派处理器看到的引脚连接方式。

步骤 0:确保你的树莓派已关闭,并且电源线已断开。

步骤 1:取一根跳线,将公针端插入面包板上的B1,母座端插入树莓派上的引脚 6 (GND)

步骤 2:取一根跳线,将公针端插入面包板上的B3,母座端插入树莓派上的引脚 3 (GPIO 20)。这是树莓派用于触发距离测量仪进行测量的连接器。

步骤 3:取 R1 680Ω(蓝灰棕)电阻 - 带蓝色色线的那个,将引脚插入面包板上的E1I2 孔中 - 电阻的方向无关紧要。

步骤 4:取另一个电阻,R2 470Ω(黄紫棕) - 带黄色色线的那个,将引脚插入面包板上的D2H2 孔中 - 方向无关紧要。

步骤 5:轻轻地将 R1 电阻弯离 R2,这样E1D2 处的引脚不会接触到(如果接触也不会损坏,只是无法工作)。

步骤 6:取一根跳线,将公针端插入面包板上的J2,母座端插入树莓派上的引脚 1 (GPIO 21)。这是树莓派用于监听测量结果的连接器。

步骤 7:取最后一根跳线,将公针端插入面包板上的B4,母座端插入树莓派上的引脚 2 (5V)

步骤 8:最后,插入 HC-SR04。它有 4 个引脚,需要插入A1A2A3A4。传感器背面,所有黑色 IC 朝向面包板,两个银色传感器指向远离面包板的方向。

启动你的树莓派。从桌面菜单中选择编程 - Python 3 (IDLE)。然后使用文件,新建文件创建一个新程序。

输入以下程序,然后使用文件,保存将程序保存为任意名称(不要忘记在末尾加上 .py)在~/python/distance 文件夹中,然后使用运行菜单,运行模块运行它。

#!/usr/bin/python

from gpiozero import DistanceSensor
from time import sleep

sensor = DistanceSensor(echo=21, trigger=20, max_distance=2.0)

while True:

   distance = sensor.distance * 100
   print("Distance : %.1f" % distance)
   sleep(1)

程序的功能

#!/usr/bin/python

第一行是注释(以 # 开头),告诉操作系统程序是用什么语言编写的。由于你将从 Python 本身运行程序,因此这行是多余的(但这是良好的做法)。

from gpiozero import DistanceSensor
from time import sleep

from 行告诉计算机学习新东西。计算机可以从其他人编写的程序中学习;我们称这些其他程序为“库”。我们的程序需要来自gpiozero 库的DistanceSensor 函数,该函数将用于与传感器进行通信,以及来自时间库的sleep 函数,以便我们插入暂停。函数只是位于其他地方的一些代码,我们可以使用它来执行某些操作。

sensor = DistanceSensor(echo=21, trigger=20, max_distance=2.0)

然后我们使用导入的DistanceSensor 函数创建一个名为sensor 的对象。我们传递的参数表明,用于触发传感器的trigger 将在 GPIO 引脚 20 上;用于监听回复的echo 将在 GPIO 引脚 21 上;应返回的最大距离为 2.0 米。

while True:

while True: 告诉程序在循环中永远运行。

   distance = sensor.distance * 100
   print("Distance : %.1f" % distance)
   sleep(1)

然后我们通过调用sensor.distance 获取当前传感器读数,将读数乘以 100(因为返回值是毫米);仅用小数点后一位输出值,最后休眠一秒,然后while True: 使我们再次进行循环。

其他说明

[编辑 | 编辑源代码]

这些说明是主教程的补充,解释了使用两个电阻制作“分压器”以及一个直接控制传感器的示例程序。

分压器

[编辑 | 编辑源代码]

树莓派是一款 3.3V 设备。本教程中使用的传感器,HC-SR04,是一款 5V 设备。这意味着传感器需要 5V 电源,并且,对于树莓派来说至关重要的是,传感器返回给树莓派的结果的电压等级也是 5V。将传感器输出直接连接到树莓派几乎肯定会损坏树莓派。

这种情况在现实世界中很常见,你想将两个设备连接在一起,但它们的电压不同。有几种方法可以解决这个问题,但最简单的方法之一,也是这里使用的方法,是使用两个电阻制作一个“分压器”,将电压从 5V 降至 3.3V 的安全值以下。

两个电阻串联放置在电源电压和零电压之间,两个电阻之间点的电压会根据两个电阻的值按比例降低。

Vout =VinR1/R1 + R2

所以,将 5V 作为 Vin 和我们使用的两个电阻的值代入,R1 = 680Ω 和 R2 = 470Ω,我们得到

Vout =Vin680/470 + 680 = 2.95V

这个 2.95V 可以安全地连接到 Pi。

一个直接与 HC-SR04 交互的程序

[编辑 | 编辑源代码]

在本教程中,我们没有直接与 HC-SR04 交互,而是将所有操作都留给了 GPIO Zero 库的 DistanceSensor 功能。这样做很方便,但有时了解确切的操作过程以及如何直接控制设备很有用。

~/python/distance 文件夹中,你会找到一个名为 rpigpio_DistanceSensor.py 的文件,它展示了如何直接触发和读取 HC-SR04 传感器,并使用 RPi.GPIO 库。

以下是触发 HC-SR04 进行测量并获取结果的代码,所有操作都包含在一个名为 measure() 的函数中。

def measure():
   # This function measures a distance
   GPIO.output(GPIO_TRIGGER, True)
   time.sleep(0.00001)
   GPIO.output(GPIO_TRIGGER, False)
 
   start = time.time()
   while GPIO.input(GPIO_ECHO)==0:
      start = time.time()
    
   while GPIO.input(GPIO_ECHO)==1:
      stop = time.time()
 
   elapsed = stop-start
   distance = (elapsed * 34300)/2
    
   return distance

这段代码是做什么的?

[编辑 | 编辑源代码]

GPIO_TRIGGER 设置为 True,休眠 10 微秒,然后将 GPIO_TRIGGER 设置为 False,这会触发传感器进行读数。

然后,代码将一个名为 start 的变量设置为当前时间,并进入一个紧密循环,只要 GPIO_ECHO 为 0(= 低),它就会在每次循环中重置 start 变量。

GPIO_ECHO 为 1(= 高)时,第一次循环将停止。此时,start 包含 Echo 引脚变高的时间。

现在,代码进入一个紧密循环,只要 GPIO_ECHO 为高,它就会在每次循环中设置 stop 变量。

最后,当 GPIO_ECHO 再次变低时,循环退出。此时,start 包含 Echo 变高的的时间,stop 包含 Echo 再次变低的时间。

现在只需进行一些数学运算即可计算出 Echo 引脚变高的持续时间,将其乘以声速(34300)并除以 2(因为传感器发出的声音是出去再回来的),我们就可以得到以厘米(cm)为单位的 distance 值。

Distancesensor-gpiozero.pdf

[编辑 | 编辑源代码]

本教程的原始 PDF 文件在维基共享资源:Distancesensor-gpiozero.pdf

Distancesensor-gpiozero-additional.pdf

[编辑 | 编辑源代码]

本教程的原始 PDF 文件在维基共享资源:Distancesensor-gpiozero-additional.pdf

rpigpio_DistanceSensor.py

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

import time
import RPi.GPIO as GPIO

# -----------------------
# Define measure function
# -----------------------
def measure():
  # This function measures a distance
  GPIO.output(GPIO_TRIGGER, True)
  time.sleep(0.00001)
  GPIO.output(GPIO_TRIGGER, False)
  start = time.time()

  while GPIO.input(GPIO_ECHO)==0:
    start = time.time()

  while GPIO.input(GPIO_ECHO)==1:
    stop = time.time()

  elapsed = stop-start
  distance = (elapsed * 34300)/2

  return distance

# -----------------------
# Main Script
# -----------------------

# Use BCM GPIO references instead of physical pin numbers
GPIO.setmode(GPIO.BCM)

# Define GPIO to use on Pi
GPIO_TRIGGER = 20
GPIO_ECHO    = 21

# Set trigger as output and echo as input
GPIO.setup(GPIO_TRIGGER,GPIO.OUT)  # Trigger
GPIO.setup(GPIO_ECHO,GPIO.IN)      # Echo

# Set trigger to False (Low)
GPIO.output(GPIO_TRIGGER, False)

# Wrap main content in a try block so we can
# catch the user pressing CTRL-C and call the
# GPIO cleanup function.
try:
  while True:
    distance = measure()
    print("Distance : %.1f" % distance)
    time.sleep(1)

except KeyboardInterrupt:
  # User pressed CTRL-C, reset GPIO settings
  GPIO.cleanup()

gpiozero_DistanceSensor.py

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

# -----------------------
# Import required Python libraries
# -----------------------
from gpiozero import DistanceSensor
from time import sleep

# -----------------------
# Main Script
# -----------------------

sensor = DistanceSensor(echo=21, trigger=20, max_distance=2.0)

while True:

  distance = sensor.distance * 100
  print("Distance : %.1f" % distance)
  sleep(1)
华夏公益教科书