第六章:构建人脸检测器和人脸识别应用程序
本章介绍以下主题:
- 人脸识别系统简介
- 构建人脸检测器应用程序
- 构建人脸识别应用程序
- 人脸识别系统的应用
介绍
近年来,人脸识别已成为最热门的研究领域之一。人脸识别系统是一种具有检测和识别人脸能力的计算机程序。为了识别一个人,它考虑他们独特的面部特征。最近,它已被应用于多个安全和监控设施,以确保高风险区域、住宅区、私人和公共建筑等的安全。
构建人脸检测器应用程序
在本节中,我们讨论了如何从网络摄像头图像中检测人脸。需要将 USB 网络摄像头连接到树莓派 3 上,以实现实时人脸检测。
如何做…
- 导入必要的包:
import cv2 import numpy as np
- 加载人脸级联文件:
frontalface_cascade= cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')
- 检查人脸级联文件是否已加载:
if frontalface_cascade.empty(): raiseIOError('Unable to load the face cascade classifier xml file')
- 初始化视频捕获对象:
capture = cv2.VideoCapture(0)
- 定义缩放因子:
scale_factor = 0.5
- 直到按下Esc键为止执行操作:
# Loop until you hit the Esc key while True:
- 捕获当前帧并调整大小:
ret, frame = capture.read() frame = cv2.resize(frame, None, fx=scale_factor, fy=scale_factor, interpolation=cv2.INTER_AREA)
- 将图像帧转换为灰度:
gray_image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
- 在灰度图像上运行人脸检测器:
face_rectangle = frontalface_cascade.detectMultiScale(gray_image, 1.3, 5)
- 绘制矩形框:
for (x,y,w,h) in face_rectangle: cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,0), 3)
- 显示输出图像:
cv2.imshow('Face Detector', frame)
- 检查是否按下了Esc键以终止操作:
a = cv2.waitKey(1) if a == 10: break
- 停止视频捕获并终止操作:
capture.release() cv2.destroyAllWindows()
人脸检测系统中获得的结果如下所示:
构建人脸识别应用程序
人脸识别是在人脸检测之后执行的一种技术。检测到的人脸与数据库中存储的图像进行比较。它从输入图像中提取特征并将其与数据库中存储的人脸特征进行匹配。
如何做…
- 导入必要的包:
import cv2 import numpy as np from sklearn import preprocessing
- 加载编码和解码任务运算符:
class LabelEncoding(object): # Method to encode labels from words to numbers def encoding_labels(self, label_wordings): self.le = preprocessing.LabelEncoder() self.le.fit(label_wordings)
- 为输入标签实现从单词到数字的转换:
def word_to_number(self, label_wordings): return int(self.le.transform([label_wordings])[0])
- 将输入标签从数字转换为单词:
def number_to_word(self, label_number): return self.le.inverse_transform([label_number])[0]
- 从输入路径提取图像和标签:
def getting_images_and_labels(path_input): label_wordings = []
- 迭代输入路径的过程并附加文件:
for roots, dirs, files in os.walk(path_input): for fname in (x for x in files if x.endswith('.jpg')): fpath = os.path.join(roots, fname) label_wordings.append(fpath.split('/')[-2])
- 初始化变量并解析输入寄存器:
images = [] le = LabelEncoding() le.encoding_labels(label_wordings) labels = [] # Parse the input directory for roots, dirs, files in os.walk(path_input): for fname in (x for x in files if x.endswith('.jpg')): fpath = os.path.join(roots, fname)
- 读取灰度图像:
img = cv2.imread(fpath, 0)
- 提取标签:
names = fpath.split('/')[-2]
- 执行人脸检测:
face = faceCascade.detectMultiScale(img, 1.1, 2, minSize=(100,100))
- 使用面部矩形迭代该过程:
for (x, y, w, h) in face: images.append(img[y:y+h, x:x+w]) labels.append(le.word_to_number(names)) return images, labels, le if __name__=='__main__': path_cascade = "haarcascade_frontalface_alt.xml" train_img_path = 'faces_dataset/train' path_img_test = 'faces_dataset/test'
- 加载人脸级联文件:
faceCascade = cv2.CascadeClassifier(path_cascade)
- 使用局部二值模式初始化人脸检测:
face_recognizer = cv2.createLBPHFaceRecognizer()
- 从训练人脸数据集中提取人脸特征:
imgs, labels, le = getting_images_and_labels(train_img_path)
- 训练人脸检测系统:
print "nTraining..." face_recognizer.train(imgs, np.array(labels))
- 测试人脸检测系统:
print 'nPerforming prediction on test images...' flag_stop = False for roots, dirs, files in os.walk(path_img_test): for fname in (x for x in files if x.endswith('.jpg')): fpath = os.path.join(roots, fname)
- 验证人脸识别系统:
predicting_img = cv2.imread(fpath, 0) # Detect faces face = faceCascade.detectMultiScale(predicting_img, 1.1, 2, minSize=(100,100)) # Iterate through face rectangles for (x, y, w, h) in face: # Predict the output index_predicted, config = face_recognizer.predict( predicting_img[y:y+h, x:x+w]) # Convert to word label person_predicted = le.number_to_word(index_predicted) # Overlay text on the output image and display it cv2.putText(predicting_img, 'Prediction: ' + person_predicted, (10,60), cv2.FONT_HERSHEY_SIMPLEX, 2, (255,255,255), 6) cv2.imshow("Recognizing face", predicting_img) a = cv2.waitKey(0) if a == 27: flag = True break if flag_stop: break
这里显示了人脸识别的输出结果:
工作原理…
人脸识别系统广泛用于实现个人安全系统。读者可以参考文章基于 OpenCV 的人脸检测系统,网址为ieeexplore.ieee.org/document/6242980/
。
另请参阅用于实时人脸检测系统的人脸检测算法研究,网址为ieeexplore.ieee.org/document/5209668
。
另请参阅
请参考以下文章:
www.ex-sight.com/technology.htm
www.eurotech.com/en/products/devices/face+recognition+systems
arxiv.org/ftp/arxiv/papers/1403/1403.0485.pdf
人脸识别系统的应用
人脸识别广泛应用于安全、医疗保健和营销领域。各行业正在利用深度学习开发新型人脸识别系统,用于识别欺诈、区分人脸和照片之间的差异等。在医疗保健领域,人脸识别结合其他计算机视觉算法用于检测面部皮肤疾病。
第七章:使用 Python 驱动硬件
在本章中,我们将涵盖以下主题:
- 控制 LED
- 响应按钮
- 控制关机按钮
- GPIO 键盘输入
- 多路复用彩色 LED
- 使用视觉持久性编写消息
介绍
树莓派计算机的一个关键特性是它能够直接与其他硬件进行接口。树莓派上的通用输入/输出(GPIO)引脚可以控制各种低级电子设备,从发光二极管(LED)到开关、传感器、电机、伺服和额外的显示器。
本章将重点介绍如何连接树莓派与一些简单的电路,并掌握使用 Python 来控制和响应连接的组件。
树莓派硬件接口由板子一侧的 40 个引脚组成。
GPIO 引脚及其布局将根据您拥有的特定型号略有不同。
树莓派 3、树莓派 2 和树莓派 B+都具有相同的 40 针布局。
树莓派 1 代老款(非 plus 型号)有一个 26 针的引脚,与新款模型的 1-26 针相同。
树莓派 2、树莓派 B+和树莓派 Plus GPIO 引脚(引脚功能)
连接器的布局如上图所示;引脚编号从 GPIO 引脚的引脚 1 开始。
引脚 1 位于最靠近 SD 卡的一端,如下图所示:
树莓派 GPIO 引脚位置
在使用 GPIO 引脚时应当小心,因为它还包括电源引脚(3V3 和 5V),以及地线(GND)引脚。所有的 GPIO 引脚都可以用作标准 GPIO,但其中一些还具有特殊功能;这些被标记并用不同颜色突出显示。
工程师通常使用 3V3 标记来指定原理图中的值,以避免使用可能被忽略的小数位(使用 33V 而不是 3.3V 会对电路造成严重损坏)。同样的方法也可以应用于其他组件的值,比如电阻,例如,1.2K 欧姆可以写成 1K2 欧姆。
TX 和 RX 引脚用于串行通信,借助电压级转换器,信息可以通过串行电缆传输到另一台计算机或设备。
我们还有 SDA 和 SCL 引脚,它们能够支持一种名为 I²C 的双线总线通信协议(树莓派 3 和 Plus 板上有两个 I²C 通道:通道 1 ARM,用于通用用途,通道 0 VC,通常用于识别 HAT 模块上连接的硬件)。还有 SPI MOSI、SPI MISO、SPI SCLK、SPI CE0 和 SPI CE1 引脚,支持另一种名为 SPI 的高速数据总线协议。最后,我们有 PWM0/1 引脚,允许生成脉冲宽度调制信号,对于伺服和生成模拟信号非常有用。
然而,在本章中,我们将专注于使用标准的 GPIO 功能。GPIO 引脚布局如下图所示:
树莓派 GPIO 引脚(GPIO.BOARD 和 GPIO.BCM)
树莓派 Rev 2(2014 年 7 月之前)与树莓派 2 GPIO 布局相比有以下不同:
- 26 个 GPIO 引脚的引脚头(匹配前 26 个引脚)。
- 引脚头旁边的另一组八个孔(P5)。详细信息如下:
树莓派 Rev 2 P5 GPIO 引脚
- 原始的树莓派 Rev 1(2012 年 10 月之前)总共只有 26 个 GPIO 引脚(匹配当前树莓派的前 26 个引脚),除了以下细节:
树莓派 Rev 1 GPIO 引脚头的差异
RPi.GPIO
库可以使用两种系统之一引用树莓派上的引脚。中间显示的数字是引脚的物理位置,也是在GPIO.BOARD模式下RPi.GPIO
库引用的数字。外部的数字(GPIO.BCM)是处理器物理端口的实际引用数字,指示哪些引脚被连接(这就是为什么它们没有特定的顺序)。当模式设置为GPIO.BCM时使用它们,并且它们允许控制 GPIO 引脚以及连接到其他 GPIO 线的任何外围设备。这包括 BCM GPIO 4 上的附加摄像头上的 LED 和板上的状态 LED。但是,这也可能包括用于读/写 SD 卡的 GPIO 线,如果干扰会导致严重错误。
如果您使用其他编程语言访问 GPIO 引脚,编号方案可能会有所不同,因此如果您了解 BCM GPIO 引用,将会很有帮助,它们指的是处理器的物理 GPIO 端口。
请务必查看附录硬件和软件清单,其中列出了本章中使用的所有物品以及您可以从哪里获得它们。
控制 LED
硬件上的hello world
等同于 LED 闪烁,这是一个很好的测试,可以确保一切正常工作,并且你已经正确地连接了它。为了让它更有趣,我建议使用红色、蓝色和绿色(RGB)LED,但如果你只有单独的 LED 也可以。
准备工作
你将需要以下设备:
- 4 x 杜邦母对公补丁线
- 迷你面包板(170 个连接点)或更大的面包板
- RGB LED(共阴)/3 个标准 LED(最好是红色、绿色和蓝色)
- 面包板线(实心线)
- 3 x 470 欧姆电阻
前面提到的每个组件成本都不会太高,并且可以在其他项目中重复使用。面包板是一个特别有用的物品,可以让你在不需要焊接的情况下尝试自己的电路:
RGB LED、标准 LED 和 RGB 电路的图表
以下图表显示了面包板电路:
连接到 GPIO 引脚的 RGB LED/标准 LED 的接线图有几种不同类型的 RGB LED 可用,因此请检查您组件的数据表以确认引脚顺序和类型。有些是 RGB 的,所以确保你按照相应的方式连接引脚,或者在代码中调整RGB_
引脚设置。你也可以获得共阳极变种,这将需要阳极连接到 3V3(GPIO 引脚 1)才能点亮(它们还需要将RGB_ENABLE
和RGB_DISABLE
设置为0
和1
)。
本书的面包板和组件图是使用一个名为Fritzing(www.fritzing.org)的免费工具创建的;它非常适合规划您自己的树莓派项目。
如何做…
- 创建
ledtest.py
脚本如下:
#!/usr/bin/python3 #ledtest.py import time import RPi.GPIO as GPIO # RGB LED module #HARDWARE SETUP # GPIO # 2[======XRG=B==]26[=======]40 # 1[=============]25[=======]39 # X=GND R=Red G=Green B=Blue #Setup Active States #Common Cathode RGB-LED (Cathode=Active Low) RGB_ENABLE = 1; RGB_DISABLE = 0 #LED CONFIG - Set GPIO Ports RGB_RED = 16; RGB_GREEN = 18; RGB_BLUE = 22 RGB = [RGB_RED,RGB_GREEN,RGB_BLUE] def led_setup(): #Setup the wiring GPIO.setmode(GPIO.BOARD) #Setup Ports for val in RGB: GPIO.setup(val,GPIO.OUT) def main(): led_setup() for val in RGB: GPIO.output(val,RGB_ENABLE) print("LED ON") time.sleep(5) GPIO.output(val,RGB_DISABLE) print("LED OFF") try: main() finally: GPIO.cleanup() print("Closed Everything. END") #End
RPi.GPIO
库将需要sudo
权限来访问 GPIO 引脚硬件,因此您需要使用以下命令运行脚本:
sudo python3 ledtest.py
运行脚本时,您应该看到 LED 的红色、绿色和蓝色部分(或者如果您使用单独的 LED,则分别点亮)。如果没有,请仔细检查您的接线或确认 LED 是否正常工作,方法是暂时将红色、绿色或蓝色线连接到 3V3 引脚(GPIO 引脚 1)。
大多数与硬件相关的脚本都需要sudo
命令,因为用户通常不会直接在这么低的层次上控制硬件。例如,设置或清除作为 SD 卡控制器一部分的控制引脚可能会损坏正在写入的数据。因此,出于安全目的,需要超级用户权限,以防止程序意外(或恶意)使用硬件。
工作原理…
要使用 Python 访问 GPIO 引脚,我们导入RPi.GPIO
库,该库允许通过模块函数直接控制引脚。我们还需要time
模块来暂停程序一定数量的秒。
然后,我们为 LED 的接线和激活状态定义值(请参阅本食谱的有更多…部分中的控制 GPIO 电流段)。
在程序使用 GPIO 引脚之前,我们需要通过指定编号方法(GPIO.BOARD
)和方向(GPIO.OUT
或GPIO.IN
)来设置它们(在这种情况下,我们将所有 RGB 引脚设置为输出)。如果引脚配置为输出,我们将能够设置引脚状态;同样,如果它配置为输入,我们将能够读取引脚状态。
接下来,我们使用GPIO.ouput()
来控制引脚,指定 GPIO 引脚的编号和我们希望它处于的状态(1
= 高/开启,0
= 低/关闭)。我们打开每个 LED,等待五秒,然后关闭它。
最后,我们使用GPIO.cleanup()
将 GPIO 引脚恢复到它们的原始默认状态,并释放对引脚的控制,以供其他程序使用。
有更多…
在树莓派上使用 GPIO 引脚必须小心,因为这些引脚直接连接到树莓派的主处理器,没有额外的保护。必须小心使用,因为任何错误的接线可能会损坏树莓派处理器,并导致其完全停止工作。
或者,您可以使用许多直接插入 GPIO 引脚排针的模块之一(减少接线错误的机会):
例如,Pi-Stop 是一个简单的预制 LED 板,模拟了一组交通信号灯,旨在成为那些对控制硬件感兴趣但又想避免损坏树莓派的人的一个过渡阶段。掌握了基础知识后,它也是一个出色的指示器,有助于调试。
只需确保您在ledtest.py
脚本中更新LED CONFIG
引脚引用,以引用您使用的硬件的引脚布局和位置。
请参阅附录中的硬件和软件清单,了解树莓派硬件零售商的清单。
控制 GPIO 电流
每个 GPIO 引脚在烧毁之前只能处理一定电流(单个引脚最大 16mA,总共 30mA),同样,RGB LED 的电流应限制在 100mA 以下。通过在 LED 之前或之后添加电阻,我们将能够限制通过 LED 的电流并控制其亮度(更大的电流将使 LED 更亮)。
由于我们可能希望同时点亮多个 LED,因此我们通常会尽量将电流设置得尽可能低,同时仍然提供足够的功率点亮 LED。
我们可以使用欧姆定律来告诉我们需要多少电阻来提供特定的电流。该定律如下图所示:
欧姆定律:电路中电流、电阻和电压之间的关系
我们将以最小电流(3mA)和最大电流(16mA)为目标,同时仍然从每个 LED 产生相当明亮的光。为了获得 RGB LED 的平衡输出,我测试了不同的电阻,直到它们提供了接近白光(通过卡片查看)。每个 LED 选择了 470 欧姆的电阻(您的 LED 可能略有不同):
需要电阻器来限制通过 LED 的电流
电阻器上的电压等于 GPIO 电压(Vgpio = 3.3V)减去特定 LED 的电压降(Vfwd);然后我们可以使用这个电阻来计算每个 LED 使用的电流,如下面的公式所示:
我们可以计算每个 LED 的电流
响应按钮
许多使用树莓派的应用程序要求在不需要连接键盘和屏幕的情况下激活操作。 GPIO 引脚为树莓派提供了一种优秀的方式,使其可以通过您自己的按钮和开关进行控制,而无需鼠标/键盘和屏幕。
准备工作
您将需要以下设备:
- 2 x DuPont 母对公跳线
- 迷你面包板(170 个连接点)或更大的面包板
- 按钮开关(瞬时闭合)或导线连接以打开/关闭电路
- 面包板导线(实心线)
- 1K 欧姆电阻器
开关如下图所示:
按钮开关和其他类型的开关以下示例中使用的开关是单极,单刀(SPST),瞬时闭合,按钮开关。单极(SP)意味着有一组使连接的触点。在这里使用的按钮开关的情况下,每侧的腿与中间的单极开关连接在一起。双极(DP)开关的作用就像单极开关,只是两侧在电上是分开的,允许您同时打开/关闭两个独立的组件。
单刀(ST)意味着开关将仅在一个位置进行连接;另一侧将保持开放。双刀(DT)意味着开关的两个位置将连接到不同的部分。
瞬时闭合意味着按下按钮时将关闭开关,并在释放时自动打开。锁定按钮开关将保持关闭状态,直到再次按下。
尝试使用树莓派的扬声器或耳机
按钮电路的布局
在此示例中,我们将使用声音,因此您还需要将扬声器或耳机连接到树莓派的音频插孔。
您需要使用以下命令安装名为flite
的程序,这将让我们让树莓派说话:
sudo apt-get install flite
安装后,您可以使用以下命令进行测试:
sudo flite -t "hello I can talk"
如果太安静(或太吵),您可以使用以下命令调整音量(0-100%):
amixer set PCM 100%
如何做…
创建btntest.py
脚本如下:
#!/usr/bin/python3 #btntest.py import time import os import RPi.GPIO as GPIO #HARDWARE SETUP # GPIO # 2[==X==1=======]26[=======]40 # 1[=============]25[=======]39 #Button Config BTN = 12 def gpio_setup(): #Setup the wiring GPIO.setmode(GPIO.BOARD) #Setup Ports GPIO.setup(BTN,GPIO.IN,pull_up_down=GPIO.PUD_UP) def main(): gpio_setup() count=0 btn_closed = True while True: btn_val = GPIO.input(BTN) if btn_val and btn_closed: print("OPEN") btn_closed=False elif btn_val==False and btn_closed==False: count+=1 print("CLOSE %s" % count) os.system("flite -t '%s'" % count) btn_closed=True time.sleep(0.1) try: main() finally: GPIO.cleanup() print("Closed Everything. END") #End
它是如何工作的…
与上一个示例一样,我们根据需要设置 GPIO 引脚,但这次是作为输入,并且还启用了内部上拉电阻器(有关更多信息,请参阅本示例的更多内容…部分中的上拉和下拉电阻器电路)使用以下代码:
GPIO.setup(BTN,GPIO.IN,pull_up_down=GPIO.PUD_UP)
在设置了 GPIO 引脚之后,我们创建一个循环,将不断检查BTN
的状态,使用GPIO.input()
。如果返回的值为false
,则表示通过开关将引脚连接到 0V(地),我们将使用flite
每次按下按钮时为我们大声计数。
由于我们在try
/finally
条件中调用了主函数,即使我们使用Ctrl + Z关闭程序,它仍将调用GPIO.cleanup()
。
我们在循环中使用短延迟;这可以确保忽略开关上的接触产生的任何噪音。这是因为当我们按下按钮时,按下或释放时并不总是完美接触,如果我们再次按下它,可能会产生多个触发。这被称为软件去抖动;我们在这里忽略了信号中的弹跳。
更多内容…
树莓派 GPIO 引脚必须小心使用;用于输入的电压应该是
在特定范围内,并且从中抽取的任何电流应该最小化使用
保护电阻。
安全电压
我们必须确保只连接在 0(地)和 3V3 之间的输入。一些处理器使用 0V 到 5V 之间的电压,因此需要额外的组件才能安全地与它们接口。除非确定安全,否则永远不要连接使用 5V 的输入或组件,否则会损坏树莓派的 GPIO 端口。
上拉和下拉电阻电路
先前的代码设置了 GPIO 引脚使用内部上拉电阻。如果 GPIO 引脚上没有上拉电阻(或下拉电阻),电压可以在 3V3 和 0V 之间自由浮动,实际逻辑状态保持不确定(有时为 1,有时为 0)。
树莓派的内部上拉电阻为 50K 欧姆至 65K 欧姆,下拉电阻为 50K 欧姆至 65K 欧姆。外部上拉/下拉电阻通常用于 GPIO 电路(如下图所示),通常使用 10K 欧姆或更大的电阻出于类似的原因(当它们不活动时提供非常小的电流吸收)。
上拉电阻允许通过 GPIO 引脚流动少量电流,并且在开关未按下时提供高电压。当按下开关时,小电流被流向 0V 的大电流所取代,因此我们在 GPIO 引脚上得到低电压。开关在按下时为活动低电平和逻辑 0。它的工作原理如下图所示:
上拉电阻电路
下拉电阻的工作方式相同,只是开关为活动高电平(按下时 GPIO 引脚为逻辑 1)。它的工作原理如下图所示:
下拉电阻电路
保护电阻
除了开关外,电路还包括与开关串联的电阻,以保护 GPIO 引脚,如下图所示:
GPIO 保护限流电阻
保护电阻的目的是保护 GPIO 引脚,如果它被意外设置为输出而不是输入。例如,假设我们的开关连接在 GPIO 和地之间。现在 GPIO 引脚被设置为输出并打开(驱动到 3V3),一旦我们按下开关,没有电阻的情况下,GPIO 引脚将直接连接到 0V。 GPIO 仍然会尝试将其驱动到 3V3;这将导致 GPIO 引脚烧毁(因为它将使用太多电流来驱动引脚到高状态)。如果我们在这里使用 1K 欧姆电阻,引脚可以使用可接受的电流驱动高(I = V/R = 3.3/1K = 3.3 毫安)。
受控关机按钮
树莓派应该始终正确关机,以避免 SD 卡损坏(在对卡进行写操作时断电)。如果您没有连接键盘或屏幕(可能正在运行自动化程序或通过网络远程控制),这可能会造成问题,因为您无法输入命令或查看您正在做什么。通过添加我们自己的按钮和 LED 指示灯,我们可以轻松地命令关机和重启,然后再次启动以指示系统处于活动状态。
准备工作
您将需要以下设备:
- 3 x DuPont 母对公跳线
- 迷你面包板(170 个连接点)或更大的面包板
- 按钮开关(瞬时闭合)
- 通用 LED
- 2 x 470 欧姆电阻
- 面包板导线(实心)
关机电路的整个布局将如下图所示:
受控关机电路布局
如何操作…
- 创建
shtdwn.py
脚本如下:
#!/usr/bin/python3 #shtdwn.py import time import RPi.GPIO as GPIO import os # Shutdown Script DEBUG=True #Simulate Only SNDON=True #HARDWARE SETUP # GPIO # 2[==X==L=======]26[=======]40 # 1[===1=========]25[=======]39 #BTN CONFIG - Set GPIO Ports GPIO_MODE=GPIO.BOARD SHTDWN_BTN = 7 #1 LED = 12 #L def gpio_setup(): #Setup the wiring GPIO.setmode(GPIO_MODE) #Setup Ports GPIO.setup(SHTDWN_BTN,GPIO.IN,pull_up_down=GPIO.PUD_UP) GPIO.setup(LED,GPIO.OUT) def doShutdown(): if(DEBUG):print("Press detected") time.sleep(3) if GPIO.input(SHTDWN_BTN): if(DEBUG):print("Ignore the shutdown (<3sec)") else: if(DEBUG):print ("Would shutdown the RPi Now") GPIO.output(LED,0) time.sleep(0.5) GPIO.output(LED,1) if(SNDON):os.system("flite -t 'Warning commencing power down 3 2 1'") if(DEBUG==False):os.system("sudo shutdown -h now") if(DEBUG):GPIO.cleanup() if(DEBUG):exit() def main(): gpio_setup() GPIO.output(LED,1) while True: if(DEBUG):print("Waiting for >3sec button press") if GPIO.input(SHTDWN_BTN)==False: doShutdown() time.sleep(1) try: main() finally: GPIO.cleanup() print("Closed Everything. END") #End
- 要使这个脚本自动运行(一旦我们测试过它),我们可以将脚本放在
~/bin
中(如果只想复制它,可以使用cp
而不是mv
),并使用以下代码将其添加到crontab
中:
mkdir ~/bin mv shtdwn.py ~/bin/shtdwn.py crontab -e
- 在文件末尾,我们添加以下代码:
@reboot sudo python3 ~/bin/shtdwn.py
Python 物联网入门指南(三)(2)https://developer.aliyun.com/article/1507200