Python 物联网入门指南(六)(2)

简介: Python 物联网入门指南(六)

Python 物联网入门指南(六)(1)https://developer.aliyun.com/article/1507314

通过 I2C 进行接口

到目前为止,一切都很好。电子电路可能非常有趣,虽然它们看起来非常复杂,但我们经常发现工作非常简单。在前一节中,我们一次只接口一个传感器。我们可以继续接口多个传感器,但我们受到现有 GPIO 数量的限制。我们还看到一些传感器,如超声波传感器可能使用多个 GPIO 引脚进行工作。这进一步减少了我们可以与微控制器接口的传感器数量。一旦我们转向更复杂的电路,我们还会意识到布线可能会变得非常混乱,如果出现问题,找出问题所在将变得非常繁琐。

现在,我们在设计机器人系统时面临的一个更大的问题是时间的问题——系统中的所有工作都必顶同步。目前大多数系统都是顺序的,即一个单元的输出成为另一个单元的输入:


现在,为了完成任务,当需要时,处理单元 1必须将输入传递给处理单元 2处理单元 3也是如此。如果数据的时间不完美,那么处理单元 2要么会一直等待处理单元 1的输入,要么更糟糕的是,处理单元 1会在处理单元 2不需要数据的时候发送数据。在这种情况下,数据将丢失,过程将出现一些错误。

因此,为了解决这个问题,当时的计算机科学家发明了一种脉冲系统。时钟脉冲是一个非常简单的方波,具有 50%的占空比(回想一下脉冲宽度调制(PWM))。电路被设计为在时钟脉冲的上升沿或下降沿执行一次操作。由于这种同步,电路的每个部分都知道何时工作。时钟脉冲的样子如下:


现在,回到问题上,我们有两个问题:

  • 机器人连接的设备/传感器存在物理限制
  • 如何使传感器和互连电路的时间协调工作

为了解决这些问题,我们使用了一个非常常用的协议,称为 I2C,代表着互联集成电路。当我们需要在相同的 GPIO 上连接多个设备时,比如只有一组 GPIO 引脚可以连接多个传感器时,这个协议非常有用。这是由于为每个硬件分配了唯一的地址。该地址用于识别传感器,然后相应地与其通信。现在,要实现 I2C 协议,我们需要两条线路;这些线路如下:

  • 数据
  • 时钟

正如你可能已经猜到的那样,时钟线用于向连接的设备发送时钟脉冲,数据是数据流动的总线。

现在,整个 I2C 架构是基于主从配置工作的,其中主设备始终为从设备生成时钟信号,从设备必须不断寻找主设备发送的时钟脉冲和数据包。让我们看看是如何完成的。

如前所述,有两条线路:数据线称为串行数据(SDA),时钟线称为串行时钟(SCL)。从现在开始,我们将使用 SCL 和 SDA 这些术语:

让我们看看图中显示的主要要点:

  • 起始条件:为了开始通信,创建一个起始条件,表示通信即将发生。主设备通过在 SCL 之前保持 SDA 线低来表示这个条件。这表示所有从设备都准备好进行通信。
  • 地址帧:一旦通信开始,主设备发送需要通信的设备的地址。这是一个 7 位地址。在每个时钟脉冲中,一个位被发送,因此需要七个时钟脉冲来发送 7 位地址。在这 7 位地址之后是读/写位。这表明设备是否在这个操作中想要写入,还是想要读取一些数据。因此,总地址帧是 8 位,需要八个时钟脉冲来发送。在这八个脉冲之后,在第九个时钟脉冲期间,主设备等待来自设备的确认。当 SDA 线被被寻址的从设备拉低时,从设备发送这个确认。通过这种策略,主设备知道它发送的地址已经被接收,并且从设备现在准备好进行通信。如果没有发送确认,那么由主设备决定接下来该做什么。
  • 数据帧:一旦确认被发送,根据是读操作还是写操作,数据要么由主设备写入从设备,要么在读操作中,数据由从设备发送到主设备。这个数据帧的长度可以是任意的。
  • 停止帧:一旦数据传输完成,主设备发出停止条件,表示通信必须停止。当 SDA 线在 SCL 线从低电平变为高电平后,此条件被执行。

这基本上就是 I2C 通信的工作原理。对于每个设备,我们有一个 7 位地址,因此我们可以在单个总线上连接多达 128 个设备。这是很多设备。几乎可以忽略物理限制用完的可能性。现在让我们继续看看如何通过这种协议连接传感器。通常,不需要为 I2C 进行核心编程,因为这很冗长和繁琐。这就是开源的魔力所在。全球有很多开发人员正在研究这些传感器,其中大多数人足够慷慨,制作了一个库并分享给大家以便编程。这些库可以在线获取,其中大多数库都处理了通信的复杂过程。

现在是我们接口第一个 I2C 设备的时候了,这是一个模拟到数字转换器。你一定会想为什么我们首先使用这个转换器。回想一下我们开始理解 GPIO 引脚的时候。这些神奇的引脚可以用作输入和输出;你可能还记得这些引脚可以是开或关状态——这些都是数字引脚,不仅在输出时,也在输入时。但是有大量的传感器是通过模拟通信工作的。由于树莓派的数字架构,直接接口这些传感器是困难的。因此,我们使用模拟到数字转换器ADC),这个转换器将传感器的模拟值转换为树莓派可以理解的数字位。

我们将连接一个 LDR,电阻将根据光线的多少改变电阻值。因此,电压将取决于光线照射在 LDR 上的多少。

现在让我们看看如何实际操作。拿起你的树莓派,让我们开始吧。首先,我们需要在树莓派上启用 I2C;按照这里列出的步骤进行操作:

  1. 打开终端(Ctrl + Shift + T
  2. 输入sudo raspi-config
  3. 选择接口选项:


  1. 然后转到高级选项:


  1. 然后选择 I2C 以启用它。然后选择是:


现在安装adafruit库以接口 ADC1115:

  1. 打开终端并复制以下命令:
sudo apt-get install build-essential python-dev python-smbus python-pip 

这个命令将库和依赖项下载到树莓派上

  1. 现在输入以下内容:
sudo pip install adafruit-ads1x15

这个命令将库和依赖项安装到树莓派上。

现在软件已经设置好了,让我们准备好硬件。按照下图将树莓派连接到 ADS1115:


准备好后,继续在 Pi 上上传这段代码:

import time
import Adafruit_ADS1x15
import RPi.GPIO as GPIO
LED =14
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED,GPIO.OUT)
adc = Adafruit_ADS1x15.ADS1115()
GAIN = 1
channel=0
adc.start_adc(channel, gain=GAIN)
while True:
    value = adc.get_last_result()
    print(str(value))
    time.sleep(0.1)
    if value >= 100:
        GPIO.output(LED,1)
    else :
        GPIO.output(LED,0)
adc.stop_adc()

请注意,有时这段代码可能不起作用,如果是这样,请尝试调整阈值的值:

if value >= 100:

你可能已经注意到,每当 LDR 面向光源时,LED 也会亮起,而当它远离光线时,LED 会熄灭。

现在你已经接口了一个 I2C 设备。让我们了解这段代码实际上是如何工作的:

import Adafruit_ADS1x15

上一行代码导入了Adafruit_ADS1x15库,以便我们在程序中使用它的所有函数。

adc = Adafruit_ADS1x15.ADS1115()

上一行代码创建了库Adafruit_ADS1x115的实例。.ADS1115()是创建实例adc的函数。明白了吗?让我用英语解释一下。

现在,我们可以简单地写adc而不是一直写Adafruit_ADS1x15,来调用库函数。此外,你可以使用任何单词代替adc;它可以是你猫的名字或你邻居的名字,它仍然可以工作:

GAIN = 1

这是传感将进行的值。1表示传感将在整个范围内进行。对于我们的 ADC 来说,范围是从 0V 到+/-4.096V 的电压范围。现在改变增益会导致传感范围的改变。也就是说,如果我们将增益值更改为2,那么传感范围将是原始范围的一半,即 0 到+/-2.048 伏。

现在你可能会问电压范围是多少,为什么我们要改变增益?

原因很简单。有不同类型的模拟传感器。它们的输出电压范围各不相同。有些传感器的输出范围是 0.5 伏到 4 伏,其他的可以是 0.1 伏到 0.98 伏。现在,如果我们将增益设置为1,那么所有这些传感器都可以轻松接口。因为它们都在 0 到 4.098 伏的感应范围内。然而,由于它是一个 16 位 ADC,因此 ADC 可以提供的离散值的总数将在 2¹⁶或 65,536 个读数之间。因此,在增益为1时,ADC 可以检测到的最小电压变化为:4.096 / 65536 = 0.000062

但是,如果增益增加到4,那么传感范围将减少到仅为0到+/-1.0245。因此,这将能够处理 0.1 伏到 0.98 伏之间的输出范围。但现在让我们看看它可以检测到的最小电压变化:1.0245 / 65536 = 0.00001563

现在你可以看到可以检测到的最小电压非常低。这对于与传感器的兼容性是一件好事。

现在,你可以决定你想要什么增益值。LDR 在 5V 上工作,因此最好使用整个增益读数为1

channel=0

当你仔细观察 ADC 硬件时,你会注意到有各种引脚,包括A0A1A2A4。这是一个四通道 ADC——它可以将四个模拟输入转换为数字数据。由于我们只使用一个数据流,我们将让 Pi 知道它连接在哪个引脚上。通过下面的代码,我们告诉 Pi 开始转换数据的过程:

adc.start_adc(channel, gain=GAIN)

在下一行中,我们指示 ADC 停止转换,代码到此结束。

adc.stop_adc()

摘要

本章主要讲述了如何将传感器与 GPIO 进行接口,以便传感器可以检索数据。

第十九章:制作园丁机器人

好了,朋友们,你已经了解了一些输入和输出的基础知识;现在是时候制作一些我们可以交出一些日常责任的东西了。这个机器人可能看起来并不像一个机器人,但相信我,它会让你的生活更轻松。最重要的是,你花园中的大部分植物都会因为你的制作而祝福你。

我们将涵盖以下主题:

  • 与电磁阀一起工作
  • 制作机器人
  • 使它更智能
  • 使它真正智能

与电磁阀一起工作

我们要做的是一个自动系统,它会在植物需要时给它们浇水。所以从技术上讲,一旦它建立起来,你就不用担心给你的绿色生物浇水了。无论你是在家里、在办公室还是度假,它都会不管任何情况下继续工作。

现在,你一定在想它是如何给植物浇水的,所以让我告诉你,对于这个世界上的每个问题,都存在一个解决方案。在我们的情况下,这个解决方案被称为电磁阀。它的基本作用是切换液体的流动。市场上有各种各样的电磁阀;一些识别特征如下:

  • 尺寸:它们有各种尺寸,如半英寸、四分之三英寸、1 英寸等。这基本上将决定电磁阀的流量。
  • 介质:无论是液体、气体、蒸汽等。
  • 正常状态
  • 通常打开:这个阀门在关闭状态下会允许液体流动——当阀门没有供电时
  • 通常关闭:这个阀门在关闭状态下会阻止液体流动——当阀门没有供电时
  • 方式数量:一个简单的阀门会有一个进口和一个出口。所以,当它打开时,它会允许液体从进口流向出口。然而,还可以有其他类型的阀门,比如三通阀,可能有两个出口和一个进口。它会调节液体的流动方向。

阀门的一些具体细节也可能会有所不同,但目前我们只需要知道这些。关于电磁阀要注意的一点是,这些阀门可以打开或关闭。无法实现这些阀门之间的任何状态或通过这些阀门控制流动。为此,我们可以使用伺服阀或电动阀。但目前我们不需要。

在本章中,我们将使用一个半英寸的水/液体阀,它通常是关闭的。当你仔细看这个阀时,你会发现它在 12 伏特下运行,电流消耗接近 1 安培。这对树莓派来说是很大的电流。树莓派每个引脚可以提供的电流上限约为 50 毫安。所以如果我们把这个阀接到树莓派上,它肯定不会工作。

我们现在该怎么办?这个问题的答案是继电器。继电器的基本工作是重新布置电路。基本上,它是一个电子控制开关。继电器的基本工作是打开和关闭具有比控制单元提供的更高电流/电压消耗的设备。这是一个相当简单的设备,正如你在图中所看到的。有两个电路。一个是蓝色的,是低电压和低电流电路。这个电路正在给线圈供电。另一个电路是红色和黑色的。这个电路是高电压、高电流电路。

在初始阶段,正如你所看到的,高电压高电流电路不完整,烤箱不会工作:


现在,在这第二个图中,你可以看到蓝色电路连接到 5V 电源,线圈被激活。每当线圈被激活,它就形成一个电磁铁,吸引高功率电路的金属片,使电路完整,从而给烤箱供电:


这就是电磁阀的工作原理。线圈的消耗几乎只有几毫安,因此通过微控制器驱动线圈非常容易。这反过来使得最终电路之间产生接触。

市场上有各种类型的继电器;一些识别特征如下:

  • 最大输出电压:它可以处理的最大电压
  • 最大输出电流:它可以承受的连接到它的任何输出设备的最大电流
  • 信号电压:它需要开关组件的电压
  • 正常条件:
  • 正常关闭:这将不允许任何电流流动,直到接收到信号为止
  • 正常开启:它将允许电流流动,直到接收到信号为止

现在,回到我们的园艺机器人,连接到它的电磁阀将在 1 安培和 12V 上工作,因此任何可以提供等于或大于 1 安培和 12V 的继电器都可以工作。

通常,市场上可用的继电器是 120V 和 12 安培直流。要记住的一件重要事情是交流电压和直流电压和电流将有两个单独的等级。由于我们的电磁阀将在 12V 下工作,我们只考虑直流的上限。

制作机器人

现在,让我们开始制作机器人。首先,您需要从水龙头到电磁阀的水管连接,从电磁阀到洒水器的连接。您还需要进行以下连接:


现在让我们开始编程。在这个机器人中,我们将接口一个土壤湿度传感器。该传感器的工作是确定土壤中的水量。通过确定这一点,我们可以了解花园是否需要水。这个土壤湿度传感器是一个模拟传感器,因此我们将使用 ADC 将模拟读数转换为树莓派可理解的数字值。所以让我们开始吧:

import time
import RPi.GPIO as GPIO
import Adafruit_ADS1x15
water_valve_pin = 23
moisture_percentage = 20
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(water_valve_pin, GPIO.OUT)
adc = Adafruit_ADS1x15.ADS1115()
channel = 0
GAIN = 1
while True:
 adc.start_adc(channel, gain=GAIN)
 moisture_value = adc.get_last_result()
 moisture_value= int(moisture_value/327)
 print moisture_value
 if moisture_value < moisture_percentage:
 GPIO.output(water_valve_pin, GPIO.HIGH)
 time.sleep(5)
 else:
 GPIO.output(water_valve_pin, GPIO.LOW)

在运行此代码之前,让我们先了解它实际上在做什么:

moisture_percentage = 20

moisture_percentage = 20是一个阈值百分比;如果土壤中的湿度水平低于 20%,那么您的花园就需要水。这是您的机器人将继续寻找的条件;一旦满足这个条件,就可以采取适当的行动。这个百分比也可以根据您花园的需要更改为3040或其他任何值:

moisture_value = int(moisture_value/327)

ADC 是一个 16 位设备——有 16 个二进制数字可以表示一个值。因此,该值可以在02¹⁵之间,换句话说,可以在032768之间。现在,很简单的数学,对于每个百分比的湿度,ADC 将给出以下读数:32768/100,或327.68。因此,要找出土壤中的湿度百分比,我们需要将 ADC 给出的实际值除以327.68

其余的代码非常简单,一旦您阅读它,您就不会很难理解。

使其更智能

祝贺您制作了您的第一个机器人!但您是否注意到了一个问题?我们制作的机器人一直在寻找湿度值,一旦注意到湿度值偏低,它就会突然泵水,并确保土壤的湿度始终高于 20%。然而,这是不必要的。一般来说,我们每天浇水一两次。如果我们浇水更多,那对植物可能不利。

因此,让我们继续使它稍微更智能化,并且只在特定时间土壤湿度低时给植物浇水。这一次,我们不需要对硬件进行任何更改;我们只需要微调代码。

让我们继续上传以下代码,然后看看到底发生了什么:

from time import sleep
from datetime import datetime
import RPi.GPIO as GPIO
import Adafruit_ADS1x15
water_valve_pin = 23
moisture_percentage = 20
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(water_valve_pin, GPIO.OUT)
adc = Adafruit_ADS1x15.ADS1115()
GAIN = 1
def check_moisture():
 adc.start_adc(0,gain= GAIN)
 moisture_value = adc.get_last_result()
 moisture_value = int(moisture_value/327)
 if moisture_value < moisture_level:
 GPIO.output(water_valve_pin, GPIO.HIGH)
 sleep(5)
 GPIO.output(water_valve_pin, GPIO.LOW)
 else:
 GPIO.output(water_valve_pin, GPIO.LOW)
while True:
 H = datetime.now().strftime('%H')
 M = datetime.now().strftime('%M')
 if H == ‘07’ and M <= ‘10’:
 check_moisture()
 if H == ‘17’ and M <= ‘01’:
 check_moisture()

这段代码可能对您来说有点陌生,但相信我,它就是这么简单。让我们一步一步地看看发生了什么:

from datetime import datetime

这行代码是从日期时间库中导入日期时间实例。这是 Python 中默认的一个库。我们只需要调用它。它的作用是在我们的代码中轻松确定时间。

def check_moisture():

有时我们必须一遍又一遍地做一些事情。这些代码集可以是几行重复的代码,也可以是多页的代码。因此,重写那些代码毫无意义。我们可以创建一个函数。在这个函数中,我们可以定义每次调用时会发生什么。在这行代码中,我们创建了一个名为check_moisture()的函数;现在,每当程序中调用这个函数时,将执行一系列活动。将要执行的一系列活动由用户定义。因此,每当我们写def时,就意味着我们正在定义一个函数;然后,我们写出需要定义的函数的名称。

完成后,然后我们在缩进中写的任何内容都将在调用函数时执行。请记住,每当我们调用或定义一个函数时,函数名称的末尾都有一个开放和关闭的()括号表示:

moisture_value = adc.get_last_result()

adc.get_last_result()adc的一个函数。它的功能是简单地从之前定义的引脚(引脚号为0)获取结果,并将读数存储到变量moisture_value中。因此,在moisture_value之后将是 ADC 引脚号0的读数,或者换句话说,是湿度传感器的读数。

H = datetime.now().strftime('%H')

代码datetime.now()的一个实例和方法。这个函数的作用是更新时间。现在,datetime.now()已经更新了日期和时间的所有参数,包括小时、分钟、秒,甚至日期。我们可以选择是否要全部或者日期和时间的任何特定部分。目前,我们想要将小时的值放入变量H中,因此我们使用了.strftime('%H')方法。strftime代表时间的字符串格式。因此,它输出的任何值都是以字符串格式。('%H')表示它只会给我们小时的值。同样,我们也可以使用('%M')('%S)来获取分钟的时间。我们还可以使用以下语法获取日期、月份和年份的值:

  • 获取日期:('%d')
  • 获取月份:('%m')
  • 获取年份:('%Y')
if H == ‘07’ and M <= ‘10’:

在前面的条件中,我们正在检查时间是否为 7 点;此外,我们还在检查时间是否小于或等于 10 分钟。因此,只有当时间为 7 小时并且在 0 到 10 分钟之间时,此代码段才会运行if语句中的语句。

特别要注意的一点是,我们在两个条件之间使用了and,因此只有在两个语句都绝对为真时才会运行其中的代码。我们还可以在其中使用一些其他语句,比如or,在这种情况下,如果其中一个语句为真,它将运行代码。

如果我们在这个if语句中用or替换and,那么它将在每个小时的 0 到 10 分钟内运行代码,并且将在上午 7:00 到 7:59 之间的整个时间内连续运行代码:

check_moisture()

正如你可能记得的,之前我们定义了一个名为check_moisture()的函数。在定义该函数时,我们还定义了每次调用该函数时将发生的一系列活动。

现在是调用该函数的时候了。一旦程序到达代码的末尾,它将执行之前在函数中定义的一系列活动。

所以我们就是这样。现在,一旦你运行这段代码,它将等待程序中定义的时间。一旦达到特定的时间,它将检查湿度。如果湿度低于设定值,它将开始给植物浇水,直到湿度超过阈值为止。

真正智能化

了不起的工作!我们已经开始自己建造比我们更聪明的东西。但现在我们想要更进一步,让它比我们更聪明——这就是机器人存在的意义。不仅仅是做我们做的事情,而是以更好的方式做所有这些。

那么,我们能做些什么改进呢?在寒冷的冬天,我们不需要太多的水,但在夏天,我们需要比冬天喝的水多得多。植物也是一样的情况。

在冬天,它们需要的水量要少得多。此外,土壤中的水蒸发速度也较慢。因此,在这两种情况下,我们需要向花园供应不同数量的水。问题是,我们该如何做到呢?

首先,要知道外面是热还是冷,我们需要一个传感器。我们将使用一个名为 DHT11 的传感器。这是一个便宜但坚固的传感器,可以给我们提供温度和湿度的读数。最好的部分是,它的价格非常便宜,大约 2 美元。

它有四个引脚。但是,如果你认为它将适用于 I2C 协议,那么你就错了。它有自己的数据传输方法。拥有一个单一的协议来处理所有传感器是很好的,但通常你也会发现有各种传感器或设备使用不同或全新的协议。DHT11 就是这样的传感器。在这种情况下,我们可以选择要么理解整个通信方法,要么简单地从制造商那里获取库并随时使用。目前我们将选择后者。

现在让我们看看 DHT11 的引脚是什么样子的:


你可以看到这里只有一个信号引脚,它将完成所有数字通信。有两个电源引脚,其中一个引脚没有使用。也就是说,这个引脚没有明显的用途。它可能只是用于焊接或将来使用。这个传感器使用 5V 电源,只需要几毫安,因此我们可以通过树莓派来为其供电。现在,对于数据通信,我们将把信号引脚连接到 GPIO 引脚号4

在我们开始编写代码之前,让我们先安装 DHT11 和树莓派之间的通信库。我们之前已经在 ADS1115 的库中做过这个,但在这个库中有一些小技巧需要我们注意。所以让我们开始吧。

首先,我们需要确保你的树莓派操作系统是最新的。所以将树莓派连接到互联网,打开树莓派的命令提示符,输入以下命令:

sudo apt-get update

这个命令将自动更新你的树莓派的 raspbian 操作系统。然后继续输入这个命令:

sudo apt-get install build-essential python-dev python-openssl

在这个命令中,我们正在安装以下软件包:

  • build-essential
  • python-dev
  • python-openssl

你一定在想为什么我们要安装所有这些。好吧,长话短说,这些是我们即将安装的 DHT11 通信库的依赖项。如果这些软件包没有安装在树莓派上,我们将无法使用该库。

最后,我们必须安装库;这是一个通用库,其中还包括与 DHT11 传感器通信的功能。这应该足以满足我们的简单通信需求。以下是安装它的命令:

sudo python setup.py install

好了,我们准备好了。我们的系统已经准备好与 DHT11 进行通信。让我们首先看看我们到目前为止所做的是否按我们想要的方式工作。为了做到这一点,按照以下方式连接 DHT11;你可以将其他组件如电磁阀和土壤湿度传感器连接好。它们不应该干扰。现在在树莓派上上传以下代码:

from time import sleep
from datetime import datetime
import RPi.GPIO as GPIO
import Adafruit_DHT
sensor = 11
pin = 4
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
while True:
 humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
 print("Temperature: " +temperature+ "C")
 print("Humidity: " +humidity+ "%")
 time.sleep(2)

一旦你上传了这段代码,你将在屏幕上看到传感器的读数。这段代码只是简单地为你提供传感器的原始读数。这段代码非常简单,你会理解其中的一切,除了一些代码行,其中包括:

import Adafruit_DHT

在代码的这一行中,我们在代码中导入了Adafruit_DHT库。这是与 DHT11 传感器通信的相同库。

sensor = 11 

DHT 有不同的版本,如 DHT11、DHT22 等。我们需要告诉程序我们使用的是哪种传感器。因此,我们已经为变量传感器分配了一个值。稍后,你将看到我们将如何使用它:

pin = 4  

在这一行中,我们将值 4 赋给一个名为pin的变量。这个变量将用于告诉程序我们已经连接了 DHT11 的树莓派引脚。

humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)

在这一行中,我们使用了Adafruit库的一个方法,名为Adafruit_DHT.read_retry()。现在,它的作用是读取 DHT 传感器,并将传感器的读数给变量humiditytemperature。需要注意的一点是,DHT11 每 2 秒更新一次读数。因此,你将在每 2 秒后收到更新的读数。

一旦这段代码完成,我们就可以确信传感器正在按我们想要的方式工作。最后,是时候将所有传感器整合在一起,制作一个完全智能的机器人了。由于电磁阀、湿度传感器和温度传感器已经连接好,我们所需要做的就是将代码上传到树莓派上,然后看魔法发生。

from time import sleep
from datetime import datetime
import RPi.GPIO as GPIO
import Adafruit_ADS1x15
import Adafruit_DHT
water_valve_pin = 23
sensor = 11
pin = 4
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(water_valve_pin, GPIO.OUT)
Channel =0
GAIN = 1
adc = Adafruit_ADS1x15.ADS1115()
def check_moisture(m):
 adc.start_adc(channel, gain=GAIN)
 moisture_value = adc.get_last_result()
 moisture_value = int(moisture_value/327)
 print moisture_value
 if moisture_value < m:
 GPIO.output(water_valve_pin, GPIO.HIGH)
 sleep(5)
 GPIO.output(water_valve_pin, GPIO.LOW)
 else:
 GPIO.output(water_valve_pin, GPIO.LOW)
while True:
 humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
 H = datetime.now().strftime(‘%H’)
 M = datetime.now().strftime(‘%M’)
 if H == ‘07’ and M <= ‘10’:
 if temperature < 15:
 check_moisture(20)
 elif temperature >= 15 and temperature < 28:
 check_moisture(30)
 elif temperature >= 28:
 check_moisture(40)
 if H == ‘17’ and M <= ‘10’:
 if temperature < 15:
 check_moisture(20)
 elif temperature >= 15 and temperature < 28:
 check_moisture(30)
 elif temperature >= 28:
 check_moisture(40)

代码很长,对吧?看起来是这样,但是一旦你逐行编写它,你肯定会明白,它可能比我们迄今为止编写的所有代码都长,但它一点也不复杂。你可能已经理解了大部分程序,但是让我解释一下我们在这里使用的一些新东西:

def check_moisture(m):
  adc.start_adc(channel, gain = GAIN)
moisture_value = adc.get_last_result()
moisture_value = int(moisture_value / 327)
print moisture_value
if moisture_value < m:
  GPIO.output(water_valve_pin, GPIO.HIGH)
  sleep(5)
  GPIO.output(water_valve_pin, GPIO.LOW)
else :
  GPIO.output(water_valve_pin, GPIO.LOW)

在这一行中,我们定义了一个名为check_moisture()的函数。以前,如果你还记得,当我们制作check_moisture函数时,我们基本上是在检查湿度值是否大于或小于 20%。如果我们需要检查 30%、40%和 50%的湿度怎么办?我们会为此制作一个单独的函数吗?

显然不是!我们所做的是向函数传递一个参数,参数基本上是放在函数括号内的变量。现在我们可以为这个变量分配值,例如check_moisture(30)-现在在执行该函数时m的值将为 30。然后,如果再次调用check_moisture(40),那么m的值将为 40。

现在,你可以看到我们在整个函数中比较m的值。

if moisture_value < m:

if 语句将检查调用函数时分配的m的值。这使我们的工作变得非常简单。

让我们看看程序的其余部分在做什么:

if temperature < 15:
                check_moisture(20)

每当达到所需的时间,它将继续检查温度。如果温度低于 15 度,它将调用函数check_moisture并将参数值设为 20。因此,如果湿度低于 20%,则会给花园浇水。

elif temperature >= 15 and temperature < 28:
                check_moisture(30)

elifelse if语句在if语句之后使用。通俗地说,这意味着如果前面的if语句不成立,它将检查这个if语句。因此,在前一行中,它将检查温度是否在 15 到 28 摄氏度之间。如果是,它将检查土壤的湿度。在这一行中,函数的参数是 30。因此,它将检查湿度是否低于 30。如果是,它将给花园供水。

elif temperature >= 28:
                check_moisture(40)

同样,在这行代码中,我们正在检查温度,如果温度等于或超过28摄氏度,那么它将把值40作为参数传递给函数check_moisture。因此,这次它将检查湿度是否达到或超过28

正如您所看到的,现在系统将检查环境温度,并根据此调节植物所需的水量。最好的部分是它是一致的,并将提供植物所需的正确水量。

本章中提到的数值仅为假设值。我强烈建议根据您所在地区和您花园中种植的植物来调整数值,以便系统发挥最佳效果。

总结

在本章中,我们涵盖了一些主题,如电磁阀集成和土壤湿度传感器,以构建一个可以自动给您的后院花园浇水的机器人。接下来,我们将介绍电机的基础知识。

第二十章:电机基础

好了!我们已经制作了一个照顾你花园的机器人,我希望它运行良好。现在是时候把事情提升到另一个水平了。

我们一直认为机器人就像 WALL-E 一样,四处移动并为我们做事。好吧,朋友,现在这个梦想并不遥远。事实上,在这一章中,我们将继续前进并制作一个。让我们看看如何做到。

我们将涵盖以下主题:

  • 基础知识
  • 让它滚动
  • 改变速度

Python 物联网入门指南(六)(3)https://developer.aliyun.com/article/1507317

相关实践学习
钉钉群中如何接收IoT温控器数据告警通知
本实验主要介绍如何将温控器设备以MQTT协议接入IoT物联网平台,通过云产品流转到函数计算FC,调用钉钉群机器人API,实时推送温湿度消息到钉钉群。
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
相关文章
|
10天前
|
数据采集 存储 XML
Python爬虫定义入门知识
Python爬虫是用于自动化抓取互联网数据的程序。其基本概念包括爬虫、请求、响应和解析。常用库有Requests、BeautifulSoup、Scrapy和Selenium。工作流程包括发送请求、接收响应、解析数据和存储数据。注意事项包括遵守Robots协议、避免过度请求、处理异常和确保数据合法性。Python爬虫强大而灵活,但使用时需遵守法律法规。
|
10天前
|
Python
深入理解Python装饰器:从入门到实践####
本文旨在通过简明扼要的方式,为读者揭开Python装饰器的神秘面纱,从基本概念、工作原理到实际应用场景进行全面解析。不同于常规的摘要仅概述内容概要,本文将直接以一段精炼代码示例开篇,展示装饰器如何优雅地增强函数功能,激发读者探索兴趣,随后深入探讨其背后的机制与高级用法。 ####
42 11
|
7天前
|
机器学习/深度学习 人工智能 TensorFlow
人工智能浪潮下的自我修养:从Python编程入门到深度学习实践
【10月更文挑战第39天】本文旨在为初学者提供一条清晰的道路,从Python基础语法的掌握到深度学习领域的探索。我们将通过简明扼要的语言和实际代码示例,引导读者逐步构建起对人工智能技术的理解和应用能力。文章不仅涵盖Python编程的基础,还将深入探讨深度学习的核心概念、工具和实战技巧,帮助读者在AI的浪潮中找到自己的位置。
|
7天前
|
机器学习/深度学习 数据挖掘 Python
Python编程入门——从零开始构建你的第一个程序
【10月更文挑战第39天】本文将带你走进Python的世界,通过简单易懂的语言和实际的代码示例,让你快速掌握Python的基础语法。无论你是编程新手还是想学习新语言的老手,这篇文章都能为你提供有价值的信息。我们将从变量、数据类型、控制结构等基本概念入手,逐步过渡到函数、模块等高级特性,最后通过一个综合示例来巩固所学知识。让我们一起开启Python编程之旅吧!
|
7天前
|
存储 Python
Python编程入门:打造你的第一个程序
【10月更文挑战第39天】在数字时代的浪潮中,掌握编程技能如同掌握了一门新时代的语言。本文将引导你步入Python编程的奇妙世界,从零基础出发,一步步构建你的第一个程序。我们将探索编程的基本概念,通过简单示例理解变量、数据类型和控制结构,最终实现一个简单的猜数字游戏。这不仅是一段代码的旅程,更是逻辑思维和问题解决能力的锻炼之旅。准备好了吗?让我们开始吧!
|
13天前
|
Java 测试技术 持续交付
【入门思路】基于Python+Unittest+Appium+Excel+BeautifulReport的App/移动端UI自动化测试框架搭建思路
本文重点讲解如何搭建App自动化测试框架的思路,而非完整源码。主要内容包括实现目的、框架设计、环境依赖和框架的主要组成部分。适用于初学者,旨在帮助其快速掌握App自动化测试的基本技能。文中详细介绍了从需求分析到技术栈选择,再到具体模块的封装与实现,包括登录、截图、日志、测试报告和邮件服务等。同时提供了运行效果的展示,便于理解和实践。
51 4
【入门思路】基于Python+Unittest+Appium+Excel+BeautifulReport的App/移动端UI自动化测试框架搭建思路
|
7天前
|
设计模式 缓存 开发框架
Python中的装饰器:从入门到实践####
本文深入探讨了Python中装饰器的工作原理与应用,通过具体案例展示了如何利用装饰器增强函数功能、提高代码复用性和可读性。读者将学习到装饰器的基本概念、实现方法及其在实际项目开发中的实用技巧。 ####
19 3
|
10天前
|
机器学习/深度学习 数据采集 数据可视化
Python在数据科学中的应用:从入门到实践
本文旨在为读者提供一个Python在数据科学领域应用的全面概览。我们将从Python的基础语法开始,逐步深入到数据处理、分析和可视化的高级技术。文章不仅涵盖了Python中常用的数据科学库,如NumPy、Pandas和Matplotlib,还探讨了机器学习库Scikit-learn的使用。通过实际案例分析,本文将展示如何利用Python进行数据清洗、特征工程、模型训练和结果评估。此外,我们还将探讨Python在大数据处理中的应用,以及如何通过集成学习和深度学习技术来提升数据分析的准确性和效率。
|
9天前
|
机器学习/深度学习 数据挖掘 开发者
Python编程入门:理解基础语法与编写第一个程序
【10月更文挑战第37天】本文旨在为初学者提供Python编程的初步了解,通过简明的语言和直观的例子,引导读者掌握Python的基础语法,并完成一个简单的程序。我们将从变量、数据类型到控制结构,逐步展开讲解,确保即使是编程新手也能轻松跟上。文章末尾附有完整代码示例,供读者参考和实践。
|
9天前
|
人工智能 数据挖掘 程序员
Python编程入门:从零到英雄
【10月更文挑战第37天】本文将引导你走进Python编程的世界,无论你是初学者还是有一定基础的开发者,都能从中受益。我们将从最基础的语法开始讲解,逐步深入到更复杂的主题,如数据结构、面向对象编程和网络编程等。通过本文的学习,你将能够编写出自己的Python程序,实现各种功能。让我们一起踏上Python编程之旅吧!