Python Arduino 编程指南(一)

原文:zh.annas-archive.org/md5/a92daa7ed7e63d78de20d04520325dc2

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

在物联网(IoT)时代,快速开发和测试你的硬件产品的原型,同时使用软件特性对其进行增强,变得非常重要。Arduino 运动在这一硬件革命中一直处于领先地位,通过其简单的板设计,它使任何人都能方便地开发 DIY 硬件项目。开源社区提供的巨大支持使得与硬件原型开发相关的困难已成为过去。在软件方面,Python 已经很长时间一直是开源软件社区的瑰宝。Python 拥有大量的库来开发各种特性,如图形用户界面、图表、消息和云应用。

本书旨在将硬件和软件世界的最佳结合带给您,帮助您使用 Arduino 和 Python 开发令人兴奋的项目。本书的主要目标是帮助读者解决将 Arduino 硬件与 Python 库接口的难题。同时,作为次要目标,本书还提供了可以用于您未来物联网项目的练习和项目。

本书的设计方式是,每一章在涵盖的材料复杂性和实用性方面都有所增加。本书分为三个概念部分(入门、实现 Python 特性、网络连接),每个部分都以一个实际项目结束,该项目整合了你在该部分学到的概念。

本书涵盖的理论概念和练习旨在让您获得 Python-Arduino 编程的实践经验,而项目旨在教授您为未来项目设计的硬件原型设计方法。然而,您仍需要在每个领域拥有广泛的专长才能开发出商业产品。最后,我希望为您提供足够的知识,以帮助您在这个新颖的物联网领域开始您的旅程。

本书涵盖的内容

第一章, Python 和 Arduino 入门,介绍了 Arduino 和 Python 平台的基础知识。它还提供了全面的安装和配置步骤,以设置必要的软件工具。

第二章, 使用 Firmata 协议和 pySerial 库,通过解释 Firmata 协议和串行接口库来讨论 Arduino 硬件与 Python 程序的接口。

第三章,第一个项目 – 运动触发 LED,提供了创建你的第一个 Python-Arduino 项目的全面指南,该项目根据检测到的运动控制不同的 LED。

第四章,深入 Python-Arduino 原型设计,带你超越我们在前一个项目中执行的基本原型设计,并提供了关于原型设计方法的深入描述,附有适当的示例。

第五章,使用 Python GUI,开始了我们用 Python 开发图形界面的两章之旅。本章介绍了 Tkinter 库,它为 Arduino 硬件提供了图形前端。

第六章,存储和绘制 Arduino 数据,涵盖了用于存储和绘制传感器数据的 Python 库、CSV 和 matplotlib。

第七章,中期项目 – 可携式 DIY 恒温器,包含了一个实用且可部署的项目,该项目利用了我们之前章节中涵盖的材料,如串行接口、图形前端和传感器数据的绘图。

第八章,Arduino 网络介绍,在利用各种协议建立 Python 程序与 Arduino 之间的以太网通信的同时,介绍了 Arduino 的计算机网络。本章还探讨了名为 MQTT 的消息协议,并提供了基本示例。该协议专门为资源受限的硬件设备,如 Arduino,而设计。

第九章,Arduino 与物联网,讨论了物联网领域,同时提供了逐步指南来开发基于云的物联网应用程序。

第十章,最终项目 – 远程家庭监控系统,教授了硬件产品的设计方法,随后是一个将云平台与 Arduino 和 Python 接口的综合项目。

第十一章,Tweet-a-PowerStrip,包含了一个基于我们在书中所学内容的另一个物联网项目。该项目探索了一种独特的将社交网络、Twitter,与 Python-Arduino 应用程序集成的途径。

你需要这本书的

首先,您只需要一台装有支持操作系统的计算机,Windows、Mac OS X 或 Linux。本书需要各种额外的硬件组件和软件工具来实现编程练习和项目。每个章节中都包含所需的硬件组件列表和获取这些组件的位置。

在软件方面,本书提供了逐步指南,用于安装和配置本书中使用的所有必要的软件包和依赖库。请注意,本书中包含的练习和项目是为 Python 2.7 设计的,并且尚未针对 Python 3+进行测试。

本书面向对象

如果您是学生、爱好者、开发者或设计师,编程和硬件原型设计经验很少或没有,并且您想开发物联网应用,那么这本书就是为您准备的。

如果您是软件开发者,并希望获得硬件领域的经验,这本书将帮助您开始。如果您是希望学习高级软件功能的硬件工程师,这本书可以帮助您开始。

约定

在本书中,您将找到许多文本样式,用于区分不同类型的信息。以下是一些这些样式的示例及其含义的解释。

文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 标签应如下显示:“在将值赋给weight变量时,我们没有指定数据类型,但 Python 解释器将其指定为整型,int。”

代码块设置如下:

/* Blink Turns on an LED on for one second, then off for one second, repeatedly. This example code isin the public domain.*/// Pin 13 has an LED connected on most Arduino boards.// give it a name:int led =13;// the setup routine runs once when you press reset: void setup(){// initialize the digital pin as an output. pinMode(led, OUTPUT);}// the loop routine runs over and over again forever: void loop(){ digitalWrite(led, HIGH);// turn the LED on (HIGH is the voltage level) delay(1000);// wait for a second digitalWrite(led, LOW);// turn the LED off by making the voltage LOW delay(1000);// wait for a second }

任何命令行输入或输出都应如下编写:

$ sudo easy_install pip 

新术语重要词汇以粗体显示。您在屏幕上看到的单词,例如在菜单或对话框中,在文本中如下显示:“在系统窗口中,点击左侧导航栏中的高级系统设置以打开名为系统属性的窗口。”

注意

警告或重要注意事项如下所示。

小贴士

小技巧如下所示。

读者反馈

我们始终欢迎读者的反馈。请告诉我们您对这本书的看法——您喜欢什么或不喜欢什么。读者反馈对我们来说很重要,因为它帮助我们开发出您真正能从中获得最大收益的书籍。

要向我们发送一般反馈,只需发送电子邮件至<[email protected]>,并在邮件主题中提及书籍的标题。

如果您在某个主题上具有专业知识,并且您对撰写或为书籍做出贡献感兴趣,请参阅我们的作者指南www.packtpub.com/authors

客户支持

现在,您已经成为 Packt 书籍的骄傲拥有者,我们有一些可以帮助您充分利用购买的东西。

下载示例代码

您可以从您在 www.packtpub.com 的账户下载示例代码文件,适用于您购买的所有 Packt Publishing 书籍。如果您在其他地方购买了这本书,您可以访问 www.packtpub.com/support 并注册,以便将文件直接通过电子邮件发送给您。

下载本书的颜色图像

我们还为您提供了一个包含本书中使用的截图/图表颜色图像的 PDF 文件。这些颜色图像将帮助您更好地理解输出的变化。您可以从以下链接下载此文件:www.packtpub.com/sites/default/files/downloads/5938OS_ColoredImages.pdf

错误清单

尽管我们已经尽一切努力确保我们内容的准确性,但错误仍然可能发生。如果您在我们的书中发现错误——可能是文本或代码中的错误——如果您能向我们报告这一点,我们将不胜感激。通过这样做,您可以节省其他读者的挫败感,并帮助我们改进本书的后续版本。如果您发现任何错误清单,请通过访问 www.packtpub.com/submit-errata,选择您的书籍,点击错误清单提交表单链接,并输入您的错误清单详情。一旦您的错误清单得到验证,您的提交将被接受,错误清单将被上传到我们的网站或添加到该标题的错误清单部分。

要查看之前提交的错误清单,请访问 www.packtpub.com/books/content/support,并在搜索字段中输入书籍名称。所需信息将出现在错误清单部分。

盗版

互联网上版权材料的盗版是一个跨所有媒体的持续问题。在 Packt,我们非常重视我们版权和许可证的保护。如果您在互联网上发现任何形式的我们作品的非法副本,请立即提供位置地址或网站名称,以便我们可以寻求补救措施。

请通过以下链接联系我们 <[email protected]>,并提供涉嫌盗版材料的链接。

我们感谢您在保护我们作者和我们为您提供有价值内容的能力方面的帮助。

问题

如果您对本书的任何方面有问题,您可以通过以下链接联系我们 <[email protected]>,我们将尽力解决问题。

第一章. Python 和 Arduino 入门

本章介绍了 Python 编程语言和开源电子原型平台 Arduino。本章的第一部分专注于 Python,并简要描述了 Python 的优势以及安装和配置步骤。本章的其余部分描述了 Arduino 及其开发环境。

在本章结束时,你将为你的操作系统配置好用于 Python 和 Arduino 的编程环境。如果你是这两个平台(即 Python 和 Arduino)的初学者,建议你遵循本章中给出的步骤,因为后续章节将假设你已经拥有了这里描述的精确配置。如果你有在这些平台上工作的经验,你可以跳到下一章。

Python 简介

自 1991 年由 Guido van Rossum 引入以来,Python 已经发展成为最广泛使用的通用、高级编程语言之一,并得到了最大的开源开发者社区的支持。Python 是一种开源编程语言,包括大量的支持库。这些库是 Python 的最好特性,使其成为最可扩展的平台之一。Python 是一种动态编程语言,它使用解释器在运行时执行代码,而不是使用编译器编译和创建可执行的字节码。

Python 开发背后的哲学是创建灵活、可读和清晰的代码,以便轻松表达概念。强调以独特的方式使用空白缩进区分 Python 与其他流行的面向高级语言。Python 支持函数式、命令式和面向对象编程,具有自动内存管理功能。

我们为什么使用 Python

Python 被认为是最容易学习的编程语言之一,对于初学者来说。与其他流行的面向对象语言如 C++和 Java 相比,Python 对程序员有以下主要优势:

  • 它易于阅读和理解
  • 它能够实现快速原型设计并减少开发时间
  • 它拥有大量的免费库包

Python 拥有一个庞大的开源社区,推动着 Python 作为编程语言的持续改进。Python 社区还负责开发大量开源库包,这些库包可以用来构建从动态网站到复杂数据分析应用的应用程序,以及开发基于简单 GUI 的应用程序来绘制复杂数学函数的图表。Python 大多数库包都系统地维护了从社区获得的代码,并定期更新。索引 Python 包数量最多的默认仓库是 PyPI (pypi.python.org)。PyPI 还提供了简单的方法来在您的操作系统上安装各种包,这将在下一节中介绍。

在与硬件平台一起工作时,有必要在硬件和您用于开发的计算机之间建立某种通信方式。在常见的计算机与硬件接口方法中,基于串口的通信是最受欢迎的,尤其是在 Arduino 平台上,它非常简单易建立。Python 提供了一个名为 pySerial 的库,它非常易于使用,并且快速实现串口接口。使用类似的库和 Python 的交互式编程能力,可以快速测试和实现您的项目想法。

现在,复杂的 物联网IoT)应用程序不仅需要串行通信支持,还需要操作系统的高级功能,如 图形用户界面GUIs),远程访问的 Web 接口,数据可视化的图表,数据分析工具,数据存储接口等。使用任何其他编程语言,如 C++ 或 Java,由于支持工具的分布式和无组织性,开发这些功能将需要大量的编程工作。幸运的是,Python 多年来在为这些类型的应用程序提供支持方面非常成功。Python 有多个库支持开发这里提到的每个功能,这些库通过 PyPI 提供。这些库是开源的,易于使用,并且得到了社区的广泛支持。这使得 Python 成为物联网应用程序的首选语言。此外,Python 还支持创建和分发您自定义构建的应用程序作为库,以便其他人也可以在他们的项目中使用它们。如果您正在为您的硬件产品开发自定义协议、API 或算法,这是一个非常有用的功能。

我们何时使用其他语言

那么,我们什么时候不应该使用 Python 来开发我们的项目呢?如前所述,Python 是一种动态语言,可以减少开发时间,但与 C、C++和 Java 等其他静态高级语言相比,它也会使您的代码执行速度变慢。这些静态语言使用编译器编译代码并创建在运行时执行的二进制文件,从而提高运行时性能。当代码的性能比更长的开发时间和更高的成本更重要时,您应该考虑这些静态语言。Python 的一些其他缺点包括内存占用大、没有适当的线程支持以及缺乏数据保护功能。简而言之,我们可以这样说,尽管 Python 提供了快速原型设计的快捷方式,但在我们完成原型测试并准备发布产品后,我们应该考虑使用其他静态高级语言进行开发。如今,这种状况正在迅速变化,公司已经开始利用 Python 来开发他们的工业产品。

注意

您可以从官方网站www.python.org获取更多与 Python 相关的信息。

安装 Python 和 Setuptools

Python 有两种版本:Python v2.x 和 Python v3.x。(在这里,x 代表适当的版本号。)虽然 Python v2.x 是一个遗留分支,并且具有更好的库支持,但 Python v3.x 是 Python 的未来。大多数 Linux 发行版和 Mac OS X 操作系统都配备了 Python,它们将 v2.x 作为首选和默认的 Python 版本。由于以下原因,本书将使用 Python v2.7 作为 Python 的默认版本:

  • 这是 Python v2.x 分支的最新版本
  • 它拥有庞大的社区支持,并且可以通过支持论坛获取其已知问题的解决方案
  • 它被大多数主要的 Python 库支持

尽管本书提供的代码示例、练习和项目应该能在任何 Python 2.7.x 变体中运行,但拥有最新版本会更好。

安装 Python

您对操作系统的喜爱是由多种因素决定的,您永远不能忽视某人对特定操作系统的偏见。因此,本书提供了三个最受欢迎的操作系统(Linux、Mac OS X 和 Windows)的安装和配置指南。让我们首先为 Linux 计算机配置 Python。

Linux

大多数 Linux 发行版都预装了 Python。要检查已安装 Python 的最新版本,请在终端窗口中使用以下命令:

$ python -V 

确保你在执行前一个命令时使用的是大写字母 V 作为选项。一旦你在终端上执行它,它将打印出你当前 Python 安装的完整版本号。如果版本是 2.7.x,那么你可以继续,你的 Linux 已经更新到了为这本书所需的 Python 的最新版本。然而,如果你有任何低于或等于 2.6.x 的版本,你将需要首先将 Python 升级到最新版本。这个过程将需要 root 权限,因为 Python 将作为一个系统组件被安装,以替换之前的版本。

Ubuntu

如果你正在使用 Ubuntu 11.10 或更高版本,你的机器上应该已经安装了 Python v2.7.x。你可以使用以下命令将 Python 升级到 v2.7.x 的最新版本:

$ sudo apt-get update && sudo apt-get --only-upgrade install python 

如果你正在运行较旧的 Ubuntu 版本(如 10.04 或更早版本),你应该有 2.6 作为默认版本。在这种情况下,你需要运行以下一系列命令来安装版本 2.7:

$ sudo add-apt-repository ppa:fkrull/deadsnakes $ sudo apt-get update $ sudo apt-get install python2.7

第一个命令将添加一个外部 Ubuntu 仓库,这将允许你安装任何版本的 Python。下一个命令将更新和索引可用的软件包列表。最后一个命令将安装 Python 2.7 的最新版本。

Fedora 和 Red Hat

Fedora 和 Red Hat Linux 也自带了 Python 作为内置包。如果你想将 Python 的版本升级到最新版本,请在终端运行以下命令:

$ sudo yum upgrade python 

小贴士

下载示例代码

你可以从你购买的所有 Packt 出版物书籍的账户中下载示例代码文件 www.packtpub.com。如果你在其他地方购买了这本书,你可以访问 www.packtpub.com/support 并注册,以便将文件直接通过电子邮件发送给你。

Windows

在 Windows 上安装和配置 Python 不像在 Linux 上那么简单。首先,你需要从 www.python.org/getit 下载 Python 的副本。

你需要小心你正在下载的 Python 版本。从你的 Windows 操作系统系统属性中检查操作系统是 32 位还是 64 位。在本书编写时,Python 的最新版本是 2.7.6。因此,下载 Python 的最新可用版本,但请确保它是 2.7.x 而不是 3.x。

对于许多第三方 Python 库,Windows 的安装二进制文件是为 32 位版本编译的。由于这个原因,我们建议你在 Windows 操作系统上安装 32 位版本的 Python。

如果您非常熟悉 Python 并且知道如何安装库,您可以安装 64 位版本的 Python。选择并运行下载的文件来安装 Python。尽管您可以将其安装到任何自定义位置,但建议使用默认安装位置,因为即将进行的配置步骤使用的是默认位置。安装完成后,您可以从开始菜单中找到 Python 命令行工具和 IDLE(Python GUI)。

尽管您可以从开始菜单打开这些工具进行基本脚本编写,但我们将修改 Windows 系统参数,以便通过 Windows 命令提示符访问 Python。为此,我们必须在环境变量中设置PATH,以便指向 Python 安装目录的位置。让我们通过右键单击我的电脑并选择属性来打开系统属性。否则,您也可以通过导航到开始 | 控制面板 | 系统和安全 | 系统来找到它。

您将能够看到一个类似于以下截图所示的窗口。系统窗口显示了您计算机的基本信息,包括您使用的 Windows 操作系统类型(例如 32 位或 64 位版本):

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_01_01.jpg

系统窗口中,点击左侧导航栏中的高级系统设置以打开一个名为系统属性的窗口。在系统属性窗口中,点击位于窗口底部的环境变量…按钮,这将打开一个类似于以下截图所示的界面。在环境变量中,您需要更新PATH系统变量,以便将 Python 添加到默认操作系统的路径中。

点击以下截图显示的PATH选项,这将弹出一个编辑系统变量窗口。在您的现有PATH变量末尾添加C:\Python27或您自定义 Python 安装目录的完整路径。在 Python 安装路径之前必须放置一个分号(;)。如果您已经在路径变量中看到了 Python 的位置,那么您的系统已经为 Python 设置了,您不需要进行任何更改:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_01_02.jpg

将 Python 添加到环境变量的主要好处是能够从命令提示符访问 Python 解释器。如果您不知道,可以通过导航到开始 | 程序 | 附件 | 命令提示符来访问 Windows 命令提示符。

Mac OS X

Mac OS X 预装了 Python,但由于操作系统的长期发布周期,默认 Python 应用程序的更新频率较慢。最新的 Mac OS X 版本,即 10.9 Maverick,配备了 Python 2.7.5,这是最新的版本:

Tests-Mac:~ test$ python Python 2.7.5(default, Aug 252013,00:04:04)[GCC 4.2.1 Compatible Apple LLVM 5.0(clang-500.0.68)] on darwin Type "help","copyright","credits"or"license"for more information.>>>

之前的版本,如 Mac OS X 10.8 Mountain Lion 和 Mac OS X 10.7 Lion 分别包含了 Python 2.7.2 和 Python 2.7.1,这些也是本书的兼容版本。如果你是一位经验丰富的 Python 用户或者想要使用 Python 最新版本的人,你可以从 www.python.org/getit 下载最新版本。

旧版本的 Mac OS X,如 Snow Leopard 及更高版本,它们附带了一个较旧的 Python 版本,可以通过从 www.python.org/getit 下载和安装来更新到最新版本。

安装 Setuptools

Setuptools 是一个包含构建和分发 Python 包的实用工具集合的库。这个集合中最重要的工具被称为 easy_install。它允许用户查看我们之前提到的 PyPI,即 Python 包仓库,并提供一个简单的接口通过名称安装任何包。easy_install 实用工具会自动下载、构建、安装和管理用户所需的包。这个实用工具在本书的后期部分被用来安装 Python 和 Arduino 即将到来的项目所需的必要包。尽管 easy_install 被用作安装 Python 包的简单方式,但它缺少了一些有用的功能,如跟踪操作、支持卸载和支持其他版本控制系统。近年来,Python 社区开始采用另一个名为 pip 的工具来替代 easy_install,它支持这些功能。由于 easy_installpip 都使用相同的 PyPI 仓库,因此从现在开始,你可以使用这些实用工具中的任何一个来安装所需的 Python 包。

为了缩小范围,我们将专注于安装 Setuptools 以及与之一起安装的默认实用工具,即 easy_install。在本节稍后,我们还将安装 pip,以防你也需要使用它。让我们首先从为各种操作系统安装 Setuptools 开始。

Linux

在 Ubuntu 中,Setuptools 可在默认仓库中找到,可以使用以下命令进行安装:

$ sudo apt-get install python-setuptools 

对于 Fedora,可以使用默认的软件管理器 yum 进行安装:

$ sudo yum install python-setuptools 

对于其他 Linux 发行版,可以使用以下单行脚本下载和构建:

$ wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O -| sudo python 

一旦在你的 Linux 发行版上安装了 Setuptools,easy_install 可以直接从终端作为内置命令访问。

Windows

与 Linux 相比,Setuptools 的安装对 Windows 来说并不那么直接。它要求用户从 pypi.python.org/pypi/setuptools 的 Windows 部分下载 ez_setup.py 文件。

下载完成后,在下载 ez_setup.py 文件的文件夹中按住 Shift 键并右键点击。选择 在此处打开命令窗口 并执行以下命令:

> python ez_setup.py 

这将在您的默认 Python 安装文件夹的Scripts文件夹中安装 Setuptools。使用我们添加 Python 到环境变量时使用的方法,现在通过将C:\Python27\Scripts添加到PATH,后面跟着分号(;)来包含 Setuptools。

这将使您能够使用easy_install将各种 Python 包安装到名为Libs的 Python 包文件夹中。一旦您将包管理器添加到环境变量中,您需要关闭并重新打开命令提示符以使这些更改生效。

Mac OS X

Setuptools 可以使用以下任何一种方法在 Mac OS X 中安装。对于初学者来说,建议使用第一种方法,因为第二种方法需要外部包管理器 Homebrew。

如果您之前从未使用过 Homebrew,您需要按照以下步骤在您的 Mac 上安装 Setuptools:

  1. pypi.python.org/pypi/setuptools的 Unix/Mac 部分下载ez_setup.py
  2. 打开终端并导航到您下载此文件的目录。对于大多数浏览器,文件会被保存在下载文件夹中。

在终端中运行以下命令以构建和设置 Setuptools:

$ sudo python ez_setup.py 

如果您熟悉基于 Homebrew 的软件安装,只需按照以下快速步骤安装 Setuptools:

一旦您安装了wget,请在终端中运行以下命令:

$ wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O -| python 

注意

更多关于 Homebrew 实用工具的信息可以从brew.sh获取。您可以通过在终端中运行以下简单脚本来在您的 Mac 上安装 Homebrew:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

首先,如果您还没有安装wget,请从 Homebrew 安装它:

$ brew install wget 

安装 pip

由于您已成功安装 Setuptools,让我们使用它来安装pip。对于 Linux 或 Mac OS X,您可以在终端中运行以下命令来安装pip

$ sudo easy_install pip 

对于 Windows,打开命令提示符并执行以下命令:

> easy_install.exe pip 

如果您已经在您的计算机上安装了pip,请确保您将其升级到最新版本以克服与升级相关的一些错误。您可以在终端使用以下命令升级pip

$ sudo easy_install --upgrade pip 

由于您已经使用easy_install安装了一个 Python 包,让我们更熟悉 Python 包管理。

安装 Python 包

安装pip后,您有两个不同的选项来安装 PyPi 存储库上列出的任何第三方 Python 包(pypi.python.org)。以下是需要了解的用于处理 Python 包安装的各种程序。在以下示例中,术语PackageName是一个用于您想要与之工作的 Python 包的伪名称。对于您选择的包,从 PyPi 网站识别适当的包名并将其名称放在PackageName的位置。在某些情况下,您需要 root(超级用户)权限来安装或卸载包。在这种情况下,您可以使用sudo后跟适当的命令。

要安装 Python 包,请在终端中执行以下命令:

$ easy_install PackageName 

否则,您还可以执行以下命令:

$ pip install PackageName 

如果您想安装特定版本的包,可以使用以下命令:

$ easy_install "PackageName==version"

如果您不知道确切的版本号,您也可以使用比较运算符,如><>=<=来指定版本号的范围。easy_installpip都会从存储库中选择最佳匹配的包版本并安装:

$ easy_install "PackageName > version"

同时,对于pip,您可以使用以下相同的命令执行类似操作:

$ pip install PackageName==version $ pip install "PackageName>=version"

例如,如果您想安装 1.0 到 3.0 之间的版本,您需要使用以下命令:

$ pip install "PackageName>=0.1,<=0.3"

使用easy_installpip升级包非常简单。两者使用的命令选项也非常相似:

$ easy_install --upgrade PackageName $ pip install --upgrade PackageName 

虽然easy_install不支持包的干净卸载,但您可以使用以下命令确保 Python 停止搜索指定的包。之后,请从安装目录中仔细删除包文件:

$ easy_install -mxN PackageName 

清理卸载大多数包的更好方法是使用pip而不是easy_install

$ pip uninstall PackageName 

在 PyPI 网站pypi.python.org/上可以找到 Setuptools 支持的 Python 包的详细列表。

Python 编程的基础知识

如果您有使用其他任何编程语言的经验,Python 入门非常容易。如果您以前从未编程过,本节将带您了解 Python 的一些基础知识。如果您已经使用过 Python,您应该跳过本节,继续下一节。

假设设置说明正确无误,让我们通过在终端或命令提示符中执行 Python 命令来打开 Python 解释器。您应该得到以下截图显示的类似结果。如果您是从网站上下载设置文件安装的 Python,那么您也应该已经安装了 Python 集成开发环境IDLE)。您也可以通过打开其安装位置处的 IDLE 来启动 Python 解释器。

正如您所看到的,在打印一些系统信息后,解释器打开了一个带有三个大于号(>>>)的提示符,这也被称为主要提示符。现在解释器处于交互模式,并准备好从提示符执行脚本。

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_01_03.jpg

要关闭 Python 解释器的交互模式,请在主要提示符下运行exit()quit(),或者使用键盘快捷键Ctrl + D

注意

注意,Python 的内置函数是区分大小写的。这意味着以下情况:

exit() ≠ EXIT() ≠ Exit()

官方 Python 网站为初学者提供了全面的教程,帮助他们开始 Python 编程。如果您正在寻找详细编程教程,而不是即将到来的简要概述,强烈建议您访问官方 Python 教程docs.python.org/2/tutorial/index.html

Python 运算符和内置类型

现在您对 Python 提示符有了初步的了解,让我们让您熟悉一些基本的 Python 命令。对于这些练习,我们将使用 Python IDLE,它也以 Python 交互提示符打开。在编写大型和复杂代码时,您需要一种方法来描述代码段、任务和注释。在所有编程语言中,不可执行的内容被称为注释,在 Python 中,它们以井号字符(#)开头。像注释一样,您将经常需要通过在提示符中使用 print 命令来检查输出:

>>># Fundamental of Python>>># My first comment>>> name ="John"# This is my name>>>print name John 

注意

除了 IDLE,您还可以从终端访问 Python 交互式提示符。当从终端使用 Python 时,请确保您正确处理缩进。

运算符

Python 支持直接从解释器使用基本数学运算符,如+、-、*和/。使用这些运算符,您可以在提示符中执行基本计算,如下面的示例所示。尝试在您的提示符中执行这些操作,以便开始使用 Python 解释器作为计算器:

>>>2+24>>>(2*3)+17>>>(2*3)/51

注意

当使用 Python 解释器时,建议您遵循 Python 代码风格指南,这通常也被称为 PEP-8 或 pep8。有关 PEP-8 的更多信息,请访问www.python.org/dev/peps/pep-0008/

内置类型

Python 是一种动态类型语言,这意味着在初始化变量时,您不必显式声明变量的类型。当您给变量赋值时,Python 解释器会自动推断数据类型。例如,让我们在解释器的交互模式下声明以下变量:

>>> weight = height =5>>> weight * height 25>>>type(weight)<type'int'>

在将值赋给 weight 变量时,我们没有指定数据类型,但 Python 解释器将其赋值为整型,int。解释器将 int 类型分配的原因是数值不包含任何小数点。现在让我们声明一个包含小数点的值的变量。可以使用 type() 内置函数来找出指定变量的数据类型:

>>> length =6.0>>> weight * height * length 150.0>>>type(length)<type'float'>

如你所见,解释器将数据类型分配为 float。解释器还可以推断复数的类型,如下面的示例所示。你可以使用点(.)运算符后跟 realimag 来访问复数的实部和虚部:

>>> val =2.0+3.9j>>> val.real 2.0>>> val.imag 3.9

为了更好地与复数进行交互,让我们尝试以下示例中的 abs()round() 函数。它们是用于获取绝对值和四舍五入数字的内置 Python 函数:

>>>abs(val)4.382921400162225>>>round(val.imag)4.0

像数字一样,Python 解释器也可以自动识别字符串数据类型的声明。在 Python 中,字符串值使用单引号或双引号包围的值来赋值。当解释器看到任何用引号包围的值时,它将其视为字符串。Python 支持使用 + 运算符来连接字符串:

>>> s1 ="Hello">>> s2 ="World!">>> s1 + s2 'HelloWorld!'>>> s1 +" "+ s2 'Hello World!'

字符类型是大小为 1 的字符串,字符串的各个字符可以通过使用索引数字来访问。字符串的第一个字符索引为 0。通过以下脚本进行实验,以了解 Python 中的索引(下标):

>>> s1[0]'H'>>> s1[:2]'He'>>> s1 + s2[5:]'Hello!'

注意

与默认符号 >>> 的主提示符类似,Python 交互式解释器在从终端使用时也有一个二级提示符,使用三个点(…)。当你使用二级提示符时,在 IDLE 中你将看不到这三个点。二级提示符用于多行结构,需要连续的行。通过手动在解释器中输入以下命令来执行,并且不要忘记在 if 语句之后用制表符缩进下一行:

>>> age =14>>>if age >10or age <20:...print"teen" teen 

数据结构

Python 支持四种主要数据结构(listtuplesetdictionary),并且围绕这些数据结构有许多重要的内置方法。

列表

列表用于将单个或多个数据类型的值组合在一起。list 结构可以通过在方括号中声明值并使用逗号(,)作为分隔符来赋值:

>>> myList =['a',2,'b',12.0,5,2]>>> myList ['a',2,'b',12.0,5,2]

像字符串一样,列表中的值可以使用索引数字来访问,索引从 0 开始。Python 使用冒号运算符的切片功能来获取数据结构中的特定子集或元素。在标准格式中,切片可以使用 myList[start:end:increment] 语法指定。以下是一些示例,以更好地理解切片的概念:

同样,您可以使用 pop() 从列表中删除元素。简单的 pop() 函数将删除列表的最后一个元素,而使用 pop(i) 可以删除特定位置的元素,其中 i 是索引数字:

>>> myList.pop()10>>> myList ['a',2,'b',12.0,5,'hello',2]>>> myList.pop(5)'hello'>>> myList ['a',2,'b',12.0,5,2]

要在特定位置添加元素,您可以使用 insert(i, x) 方法,其中 i 表示索引值,而 x 是您想要添加到列表的实际值:

>>> myList.insert(5,'hello')>>> myList ['a',2,'b',12.0,5,'hello',2,10]

您还可以执行各种操作以在现有列表中添加或删除元素。例如,如果您想在列表末尾添加一个元素,请使用列表上的 append() 方法:

>>> myList.append(10)>>> myList ['a',2,'b',12.0,5,2,10]

您可以使用 len() 方法检查列表变量的长度。此方法在即将到来的项目中将非常有用:

>>>len(myList)6

您可以通过提供起始值和结束值来获取列表的每个其他元素:

>>> myList[0:5:2]['a','b',5]

使用减号和索引数字的组合告诉解释器使用该索引数字的反向。在以下示例中,-1 反向实际上代表索引数字 5

>>> myList[1:-1][2,'b',12.0,5]

您可以提供起始和结束索引值以获取列表的特定子集:

>>> myList[1:5][2,'b',12.0,5]

你可以通过使用空起始和结束值来访问列表中的所有元素:

>>> myList[:]['a',2,'b',12.0,5,2]

你可以如下访问列表中的一个元素:

>>> myList[0]'a'

元组

元组是 Python 支持的不可变数据结构(与列表的可变结构不同)。不可变数据结构意味着您不能从元组数据结构中添加或删除元素。由于它们的不可变属性,元组比列表访问更快,通常用于存储一组不变的值,这些值永远不会改变。

tuple 数据结构声明方式与 list 相同,但使用括号或没有任何括号:

>>> tupleA =1,2,3>>> tupleA (1,2,3)>>> tupleB =(1,'a',3)>>> tupleB (1,'a',3)

就像在 list 数据结构中一样,tuple 中的值可以使用索引数字访问:

>>> tupleB[1]'a'

由于元组是不可变的,因此列表操作方法(如 append()insert()pop())不适用于元组。

集合

Python 中的 set 数据结构实现用于支持数学集合操作。set 数据结构包括一个无序的元素集合,没有重复项。由于其数学用例,此数据结构主要用于在列表中查找重复项,因为使用 set() 函数将列表转换为集合会从列表中删除重复项:

>>> listA =[1,2,3,1,5,2]>>> setA =set(listA)>>> setA set([1,2,3,5])

字典

dict 数据结构用于通过键索引存储键值对,在其他语言中也被称为关联数组、散列或哈希表。与其他数据结构不同,dict 的值可以通过关联键提取:

>>> boards ={'uno':328,'mega':2560,'lily':'128'}>>> boards['lily']'128'>>> boards.keys()['lily','mega','uno']

注意

您可以在 docs.python.org/2/tutorial/datastructures.html 了解更多关于 Python 数据结构和相关方法的信息。

控制程序流程

就像任何其他语言一样,Python 支持使用复合语句控制程序流程。在本节中,我们将简要介绍这些语句。您可以从官方 Python 文档docs.python.org/2/reference/compound_stmts.html中获取有关它们的详细信息。

if语句

if语句是最基本和最标准的语句,用于设置条件流程。为了更好地理解if语句,请在 Python 解释器中执行以下代码,并使用不同的age变量值:

>>> age =14>>>if age <18and age >12:print"Teen"elif age <13:print"Child"else:print"Adult"

这将在解释器上打印出Teen

for语句

Python 的for语句按照序列中元素的顺序遍历任何序列的元素:

>>> celsius =[13,21,23,8]>>>for c in celsius:print" Fahrenheit: "+str((c *1.8)+32)

这将导致 Python 解释器生成以下输出,显示从给定的摄氏值计算出的华氏值:

Fahrenheit:55.4 Fahrenheit:69.8 Fahrenheit:73.4 Fahrenheit:46.4

while语句

while语句用于在 Python 程序中创建连续循环。while循环会持续迭代代码块,直到条件被证明为真:

>>> count =5>>>while(count >0):print count count = count -1

while语句将不断迭代并打印变量count的值,同时将其值减 1,直到条件(即count > 0)为真。一旦count的值低于或等于 0,while循环将退出代码块并停止迭代。

Python 支持的其他复合语句是try/catchwith。这些语句将在接下来的章节中详细介绍。Python 还提供了循环控制语句,如breakcontinuepass,可以在使用前面提到的复合语句执行循环时使用。您可以从docs.python.org/2/tutorial/controlflow.html了解更多有关这些 Python 特性的信息。

内置函数

Python 支持许多有用的内置函数,这些函数不需要导入任何外部库。我们已经根据它们的函数特性将这些函数描述为各自类别的集合。

转换

转换方法,如int()float()str()可以将其他数据类型分别转换为整数、浮点型或字符串数据类型:

>>> a ='a'>>>int(a,base=16)10>>> i =1>>>str(i)'1'

类似地,可以使用list()set()tuple()将一种数据结构转换为另一种数据结构。

数学运算

Python 还支持内置的数学函数,可以从列表中找到最小值和/或最大值。查看以下示例,并尝试不同的数据结构来理解这些方法:

>>>list=[1.12,2,2.34,4.78]>>>min(list)1.12>>>max(list)4.78

pow(x,y)函数返回xy次幂:

>>>pow(3.14159,2)9.869587728099999
字符串操作

Python 通过内置函数提供对字符串操作的简单访问,这些函数针对性能进行了优化。让我们看看以下示例:

用于将整个字符串值转换为大写或小写的代码:

>>>str="Hello World!">>>str.upper()'HELLO WORLD!'>>>str.lower()'hello world!'

注意

官方网站上的 Python 文档详细介绍了每个内置函数及其示例。为了更好地理解 Python 编程,请访问 docs.python.org/2/library/functions.html

用于使用任何其他分隔字符分割字符串的代码:

>>> str2 ="John, Merry, Tom">>> str2.split(",")['John',' Merry',' Tom']

用于使用分隔字符分割字符串的代码,其中默认字符是空格:

>>>str="Hello World!">>>str.split()['Hello','World!']

用于替换字符串或子字符串出现的代码:

>>>str="Hello World!">>>str.replace("World","Universe")'Hello Universe!'

Arduino 简介

任何需要计算或与其他计算机接口的电子产品,首先需要使用简单工具快速原型化其概念。Arduino 是一个围绕流行的微控制器系列设计的开源硬件原型平台,它包括一个简单的软件开发环境。除了原型化之外,你还可以使用 Arduino 来开发自己的自己动手做DIY)项目。Arduino 通过让你简单地将传感器和执行器与计算机连接起来,将计算世界与物理世界连接起来。基本上,你可以通过使用 Arduino 的输入/输出引脚和微控制器来编写代码,监控和控制你日常生活中的各种电子组件。这些组件的例子包括电机、恒温器、灯光、开关等等。

历史

2005 年,Arduino 的意大利联合创始人 Massimo Banzi 为他在互动设计学院伊夫雷亚IDII)的学生开发了这项技术。从那时起,Arduino 已经发展成为最大的开源硬件平台之一。Arduino 设计的所有软件组件和原理图都是开源的,你可以以非常低的价格购买硬件——大约 30 美元——或者你也可以自己制作它。

为什么选择 Arduino?

Arduino 社区的主要目标是持续改进 Arduino 平台,以下是一些考虑的目标:

  • Arduino 平台应该是一个经济实惠的平台
  • 它应该易于使用和编码
  • 它应该是一个开源和可扩展的软件平台
  • 它应该是一个开源和可扩展的硬件平台
  • 它应该有社区支持的 DIY 项目

这些简单但强大的目标使 Arduino 成为一种流行的广泛使用的原型平台。Arduino 使用基于流行的 AVR 硬件架构的 Atmel ATmega 系列微控制器。对 AVR 架构的巨大支持也使 Arduino 成为首选的硬件平台。以下图像显示了 Arduino 板的基本版本,称为 Arduino Uno(在意大利语中,Uno 意味着“一个”):

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_01_04.jpg

Arduino 变体

任何项目,硬件需求都是由项目规格决定的。如果你正在开发一个需要与大量外部组件接口的项目,你需要一个具有足够数量的输入/输出I/O)引脚的实验平台来进行接口。如果你正在从事一个需要进行大量复杂计算的项目,你需要一个计算能力更强的平台。

幸运的是,Arduino 板有 16 种不同的官方版本,每个版本的 Arduino 在形态、计算能力、I/O 引脚和其他板载功能方面与其他版本不同。Arduino Uno 是基本且最受欢迎的版本,对于简单的 DIY 项目来说已经足够。对于本书中的大多数练习,我们将使用 Arduino Uno 板。你也可以使用另一个流行的变体,即 Arduino Mega,这是一个更大的板,具有额外的引脚和强大的微控制器。以下表格显示了 Arduino 板一些更受欢迎和活跃的变体的比较:

名称处理器处理器频率数字 I/O数字 I/O(带 PWM)模拟 I/O
Arduino UnoATmega32816 MHz1466
Arduino LeonardoATmega32u416 MHz14612
Arduino MegaATmega256016 MHz541416
Arduino NanoATmega32816 MHz1468
Arduino DueAT91SAM3X8E84 MHz541212
LilyPad ArduinoATmega168v 或 ATmega328v8 MHz1466

这些任何一种变体都可以使用一个称为Arduino IDE的通用集成开发环境进行编程,这将在下一节中描述。你可以根据项目需求选择这些 Arduino 板中的任何一个,Arduino IDE 应该能够编译并将程序下载到板子上。

Arduino Uno 板

由于 Arduino Uno 将是本书中大多数项目的实际板,让我们熟悉一下该板。Uno 板最新版本基于 Atmel 的 ATmega328 微控制器。该板将微控制器的 I/O 引脚扩展到外围,然后可以通过电线利用这些引脚来接口组件。该板共有 20 个引脚用于接口,其中 14 个是数字 I/O 引脚,6 个是模拟输入引脚。在 14 个数字 I/O 引脚中,6 个引脚也支持脉冲宽度调制PWM),这支持对连接组件的功率进行控制性传输。

该板在 5V 电压下工作。数字 I/O 引脚的最大电流额定值为 40 mA,足以驱动大多数 DIY 电子元件,但不包括对高电流有要求的电机。

尽管前面的图像提供了 Uno 板的概述,但以下图表描述了 Uno 板上的引脚。如图所示,数字引脚位于板的一侧,而模拟引脚位于另一侧。板子上还有几个电源引脚,可以用来为外部组件提供 5V 和 3.3V 的电源。板子的两侧也有地线引脚。我们将广泛使用 5V 的电源和地线引脚来完成我们的项目。数字引脚 D0D1 分别通过 Tx传输)和 Rx接收器)接口支持串行接口。板上的 USB 端口可以用来将 Arduino 连接到计算机。

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_01_05.jpg

既然我们已经熟悉了 Arduino 硬件,让我们继续学习如何编程 Arduino 板。

安装 Arduino IDE

开始熟悉 Arduino 的第一步是安装 Arduino 集成开发环境IDE)。根据 Python 安装部分开始时选择的操作系统,遵循适当的子部分来安装正确的 IDE。

Linux

在 Ubuntu 上安装 Arduino IDE 非常简单。Ubuntu 仓库已经包含了带有所需依赖项的 Arduino IDE。

对于 Ubuntu 12.04 或更新的版本,请在终端中执行以下命令来安装 Arduino:

$ sudo apt-get update && sudo apt-get install arduino arduino-core 

Ubuntu 仓库中 Arduino IDE 的最新版本是 1.0.3。有关其他 Ubuntu 相关问题的更多信息,请参阅playground.arduino.cc/Linux/Ubuntu

对于 Fedora 17 或更新的 Red Hat Linux 版本,请在终端中执行以下脚本:

$ sudo yum install arduino 

可以在playground.arduino.cc/Linux/Fedora获取 Fedora 的附加安装问题的答案。

Mac OS X

要在 Mac OS X(10.7 或更高版本)上安装 Arduino IDE,请执行以下步骤:

  1. arduino.cc/en/Main/Software下载适用于 Mac OS X 的最新版本的 Arduino IDE,当本书编写时,版本是 1.0.5。
  2. 解压并将 Arduino 拖到应用程序文件夹中。

Arduino IDE 是用 Java 编写的,需要您的计算机配备适当的 Java 版本。从您的应用程序中打开 IDE。如果您在 Mac 上没有安装 Java,程序将弹出一个窗口并要求您安装 Java SE 6 运行时。按照要求安装 Java(因为 OS X 会自动为您安装)。

Windows

Windows 上 Arduino 的安装非常简单。从arduino.cc/en/Main/Software下载设置文件。选择 Arduino IDE 的最新版本,即 1.0.x 或更新的版本。

确保根据您的操作系统下载适当的 Arduino IDE 版本,即 32 位或 64 位。按照安装向导中指定的默认位置安装 IDE。安装完成后,您可以通过导航到开始 | 程序来打开 IDE。

开始使用 Arduino IDE

Arduino IDE 是一个使用 Java 开发的跨平台应用程序,可以用来开发、编译和上传程序到 Arduino 板。启动 Arduino IDE 后,您将看到一个类似于以下截图所示的界面。IDE 包含一个用于编码的文本编辑器、一个菜单栏以访问 IDE 组件、一个工具栏以方便访问最常用的功能,以及一个文本控制台以检查编译器的输出。底部状态栏显示所选的 Arduino 板及其连接的端口号,如下所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_01_06.jpg

什么是 Arduino 草图?

使用 IDE 开发的 Arduino 程序称为草图。草图是用 Arduino 语言编写的,该语言基于 C/C++的定制版本。一旦您在内置文本编辑器中编写完代码,您可以使用.ino扩展名保存它。当您保存这些草图文件时,IDE 会自动创建一个文件夹来存储它们。如果您为草图使用任何其他支持文件,例如头文件或库文件,它们都将存储在此位置(也称为草图簿)。

要打开一个新的草图簿,打开 Arduino IDE 并从文件菜单中选择新建,如下面的截图所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_01_09.jpg

您将看到一个空白的文本编辑器。文本编辑器支持标准功能(即,复制/粘贴、选择、查找/替换等)。在我们继续 Arduino 程序之前,让我们探索 IDE 提供的其他工具。

注意

在 1.0 版本之前的 Arduino IDE 使用.pde扩展名来保存草图簿。从 1.0 版本开始,它们使用.ino扩展名保存。您仍然可以在最新版本的 IDE 中打开具有.pde扩展名的文件。稍后,当您保存它们时,IDE 将将其转换为.ino扩展名。

使用库

Arduino IDE 使用库来扩展现有草图的功能。库是一组组合在一起以执行围绕特定组件或概念的任务的函数。大多数内置的 Arduino 库提供与外部硬件组件开始工作的方法。您可以通过导航到草图 | **导入库…**来导入任何库,如下面的截图所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_01_07.jpg

您也可以通过在草图的开头使用#include语句指定库来为您的草图使用库,即#include <Wire.h>

Arduino IDE 还提供了添加支持特定硬件或提供额外功能的库的能力。在接下来的章节中,我们将处理一些这些外部库,并且我们将在那时介绍导入它们的过程。

你可以从arduino.cc/en/Reference/Libraries了解更多关于内置 Arduino 库的信息。

使用 Arduino 示例

Arduino IDE 包含大量的内置示例草图。这些示例旨在让用户熟悉基本的 Arduino 概念和内置 Arduino 库。Arduino 社区对这些示例进行了良好的维护,因为它们通过 Arduino 网站(arduino.cc/en/Tutorial/HomePage)为每个示例提供了全面的支持。在 Arduino IDE 中,你可以通过导航到文件 | 示例来访问这些示例,如下面的截图所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_01_10.jpg

让我们从简单的内置示例开始。通过导航到文件 | 示例 | 01.基础 | 闪烁来打开闪烁示例。IDE 将打开一个新窗口,其中包含与以下程序类似的代码:

/* Blink Turns on an LED on for one second, then off for one second, repeatedly. This example code isin the public domain.*/// Pin 13 has an LED connected on most Arduino boards.// give it a name:int led =13;// the setup routine runs once when you press reset: void setup(){// initialize the digital pin as an output. pinMode(led, OUTPUT);}// the loop routine runs over and over again forever: void loop(){ digitalWrite(led, HIGH);// turn the LED on (HIGH is the voltage level) delay(1000);// wait for a second digitalWrite(led, LOW);// turn the LED off by making the voltage LOW delay(1000);// wait for a second }

这个 Arduino 草图被设计用来在数字引脚 13 上闪烁一个 LED。你可能想知道为什么我们没有讨论或要求你带来任何硬件。那是因为 Arduino Uno 板子上配备了一个连接到数字引脚 13 的板上 LED。现在,我们不再深入 Arduino 代码,而是将重点放在通过 IDE 处理 Arduino 板的过程上。

编译和上传草图

一旦你在 IDE 中打开了代码,你需要做的第一件事就是选择你将要上传草图的 Arduino 板类型。Arduino IDE 需要知道板子的类型,以便为适当的微控制器编译程序,因为不同的 Arduino 板可能具有不同的 Atmel 微控制器。因此,在你继续编译或上传程序到板子之前,你需要执行这一步。

你可以通过导航到工具 | 来选择 Arduino 板,如下面的截图所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_01_08.jpg

从板子列表中选择 Arduino Uno,除非你使用的是不同的 Arduino 板。一旦你选择了板子,你就可以继续编译草图。你可以通过导航到菜单栏中的草图 | 验证/编译来编译草图,或者使用键盘快捷键Ctrl + R。如果一切设置得当,你应该能够编译代码而不会出现任何错误。

在成功编译草图后,是时候将编译好的代码上传到 Arduino 板上了。为此,您需要确保您的 Arduino IDE 已经正确连接到您的计算机。如果尚未连接,请使用 USB 端口将 Arduino 板连接到您的计算机。现在,您需要让 IDE 知道板连接的串行端口。导航到工具 | 串行端口并选择合适的串行端口。

注意

在某些 Linux 发行版的情况下,由于串行端口上的权限限制,您可能无法看到或上传 Arduino 程序到板子上。在终端运行以下命令应该可以解决这个问题:

$ sudo usermod -a -G uucp, dialout, lock <username>

您现在可以通过导航到文件 | 上传将编译好的草图上传到您的 Arduino 板。这个过程将使用串行连接在微控制器中烧录编译好的固件。请等待一段时间,或者直到板上的 LED(Tx 和 Rx LED)停止闪烁。现在,您的 Arduino 板已经准备好了,您的第一个草图也已经上传。您可以观察靠近数字引脚 13 处闪烁的 LED 的性能。

使用串行监视器窗口

在前面的过程中,我们使用通用串行总线(USB)电缆将您的 Arduino 板连接到计算机的 USB 端口。USB 端口是一个工业标准,用于通过串行接口连接各种电子组件到计算机。当您使用 USB 连接 Arduino 板时,计算机实际上将其作为串行外围设备进行接口。在整个书中,我们将使用 USB 连接称为串行连接。串行监视器窗口是 Arduino IDE 的一个内置实用工具。可以通过导航到工具 | 串行监视器或使用Ctrl + Shift + M键盘快捷键访问串行监视器窗口。它可以配置为观察通过连接 Arduino 板到计算机的串行端口发送或接收的数据。您还可以使用下拉菜单选项设置串行通信的波特率。当测试原型及其性能时,这个实用工具(在本书的后续部分)将非常有用。

Arduino 编程简介

Arduino 平台被引入是为了简化每个人的电子硬件原型设计。因此,Arduino 编程旨在让非程序员,如设计师、艺术家和学生,容易学习。Arduino 语言是用 C/C++实现的,而草图和程序结构的基本原理来源于一个名为Processing的开源编程语言和一个名为Wiring的开源电子原型设计语言。

注释

Arduino 采用了从 C 语言继承的注释格式,并且与高级语言类似;然而,它与我们在本章 earlier 学习的 Python 注释格式不同。有各种注释方法,如下所示:

单行或内联注释: 这是通过在行前使用 // 来实现的:

// This syntax only applies to one line.// You have to use it again for each next line of comment.int pin =13;//Selected pin 13

块注释: 这是通过在 /**/ 之间覆盖注释文本来实现的:

/* This is a comment.* Arduino will ignore any text till it finds until the ending comment syntax, which is,*/

通常,在草图开头的块注释主要用于描述整个程序。单行注释用于描述特定的函数或待办事项,如下所示:

//TODO: explain variables next.

变量

与任何其他高级语言一样,变量用于通过三个组件来存储数据:名称、值和数据类型。例如,考虑以下语句:

int pin =10;

在这里,pin 是一个使用 int 类型定义的变量名,并持有值 10。在代码的后续部分,所有 pin 变量的出现都将从我们刚才在这里做出的声明中检索数据。只要第一个字符不是数字,你可以使用任何 alpha-numeric 字符组合来选择变量名。

常量

在 Arduino 语言中,常量是预定义的变量,用于简化程序:

  • HIGH, LOW: 在与 Arduino 板上的数字引脚一起工作时,这些引脚上只有两种不同的电压状态是可能的。如果一个引脚被用来获取输入,任何超过 3V 的测量值都被认为是 HIGH 状态。如果你使用一个引脚作为输出,那么 HIGH 状态将设置引脚电压为 5V。相反的电压级别被认为是 LOW 状态。
  • false, true: 这些用于表示逻辑上的真和假级别。false 被定义为 0,而 true 通常被定义为 1
  • INPUT, OUTPUT: 这些常量用于定义 Arduino 引脚的角色。如果你将 Arduino 引脚的模式设置为 INPUT,Arduino 程序将准备引脚来读取传感器。同样,OUTPUT 设置将引脚准备为向连接的传感器提供足够的电流。

我们将在本书的后续部分使用这些常量,并使用示例代码来解释它们。

数据类型

每个自定义变量的声明都需要用户指定与变量关联的数据类型。Arduino 语言使用一组标准的数据类型,这些数据类型在 C 语言中使用。以下列出了这些数据类型及其描述:

array: array 存储一组变量集合,可以通过索引号访问。如果你熟悉 C/C++ 中的数组,那么开始使用 Arduino 语言将更容易,因为 Arduino 语言使用相同的 C/C++ 数组。以下是一些初始化数组的示例方法:

int myIntArray[]={1,2,3,4,5};int tempValues[5]={32,55,72,75}; char msgArray[10]="hello!";

可以使用索引号(索引从数字 0 开始)访问数组:

myIntArray[0]==1 msgArray[2]=='e'

char: 这种数据类型存储一个字符值,并占用 1 字节内存。当为 char 数据类型提供值时,字符字面量用单引号声明:

char myCharacater ='P';

float: 这种数据类型用于有小数点的数字。这些也被称为浮点数。float 是在 Arduino 语言中表示数字的更广泛使用的数据类型之一,与 int 一起使用:

float varFloat =1.111;

int: 这是整数的简称。它存储 16 位(Arduino Uno)或 32 位(Arduino Due)数字,并且是 Arduino 语言的主要数字存储数据类型之一。尽管本书中将使用 int 来声明数字,但 Arduino 语言还有 longshort 数字数据类型用于特殊情况:

int varInt =2147483647;long varLong = varInt; short varShort =-32768;

字节型: 这用于存储一个 8 位无符号数,基本上是从 0 到 255 的任何数字:

byte b =0xFF;

布尔型: 使用数据类型 布尔型 定义的变量只能持有两个值之一,truefalse:

boolean ledState = false;

void: 这在函数声明中使用,表示该函数不会返回任何值:

void setup(){// actions }

转换

转换函数用于将任何数据类型值转换为提供的数据类型。Arduino 语言实现了以下转换函数,这些函数可以在编程过程中使用:

  • char(): 这将任何数据类型的值转换为字符数据类型
  • byte(): 这将任何数据类型的值转换为字节数据类型
  • int(): 这将任何数据类型的值转换为整数数据类型
  • float(): 这将任何数据类型的值转换为浮点数数据类型

作为使用这些函数的演示,请查看以下示例:

int myInt =10;float myfloat =float(myInt);

前述代码的实现将创建一个浮点变量 myFloat,其值为 10.0,使用由 myInt 变量初始化的整数值。

函数和语句

函数,也称为子程序过程,是一段用于执行特定任务的代码。Arduino 语言提供了一些预定义的函数,用户也可以编写自定义函数以实现特定的程序逻辑。这些自定义函数可以从脚本的任何部分调用以执行特定任务。函数有助于程序员简化调试,减少错误发生的可能性,并组织编码概念:

void blinkLED(){// action A;// action B;}

Arduino 语言提供了一套库函数,用于简化编程体验。尽管并非所有这些库函数都是 Arduino 脚本所必需的,但 setup()loop() 是强制性的函数,并且它们对于成功编译脚本是必需的。

setup() 函数

当 Arduino 运行一个草图时,它首先查找setup()函数。setup()函数用于在程序的其他部分之前执行重要的编程子例程,例如声明常量、设置引脚、初始化串行通信或初始化外部库。当 Arduino 运行程序时,它只执行一次setup()函数。如果你查看我们在上一节中使用的闪烁草图,你可以看到setup()函数的初始化,如下面的代码片段所示:

void setup(){// initialize the digital pin as an output. pinMode(led, OUTPUT);}

正如你在我们的示例中看到的那样,我们使用了pinMode()函数在setup()函数中分配 LED 引脚的角色。

loop()函数

一旦 Arduino 执行了setup()函数,它就开始连续迭代loop()函数。setup()函数包含初始化参数,而loop()函数包含你程序的逻辑参数:

void loop(){ digitalWrite(led, HIGH); delay(1000); digitalWrite(led, LOW); delay(1000);}

正如你在前面的代码片段中看到的那样,闪烁草图中的loop()函数执行了主要的代码,该代码使 LED 闪烁并重复迭代过程。

pinMode()函数

pinMode()函数用于设置 Arduino 的行为。正如我们在闪烁草图的setup()函数中看到的那样,pinMode()函数配置 LED 引脚为OUTPUT

pinMode(led, OUTPUT)

在这里,led变量被分配到数字引脚 13,其模式将由pinMode()函数更改。

处理引脚

一旦你完成了配置程序将使用的引脚,你还需要帮助读取这些引脚的输入或向它们发送信号。Arduino 提供了一些特定的函数来处理这些场景:

  • analogWrite():此函数用于在数字引脚上提供模拟输出结果。该技术称为 PWM,这将在第四章深入 Python-Arduino 原型设计中解释。仍然需要注意的是,此函数并非为所有数字引脚设计,而仅适用于指定为 PWM 引脚的引脚。

analogRead():此函数从特定的模拟引脚读取值。该值在 0 和 1023 的整数值之间线性映射,以表示从 0V 到 5V 的电压:

value = analogRead(0);

digitalRead():与digitalWrite()类似,此函数帮助你读取配置为INPUT的数字引脚的状态:

value = digitalRead(13);

digitalWrite():这是为数字 I/O 引脚开发的。此函数将引脚设置为HIGH(5V)或LOW(0V),这些引脚已经通过pinMode()配置为OUTPUT。例如,以下代码行将数字引脚 13 设置为HIGH

digitalWrite(13, HIGH);

语句

如果你熟悉任何其他面向对象的编程语言,你肯定在程序中广泛使用了语句。Arduino 语言使用传统的 C/C++语句,如if/elsewhileswitch/casefor来控制程序的流程。现在我们不深入探讨这些语句,它们将在书中通过实际例子进行描述。

摘要

好的!你已经成功完成了相对平凡的安装和配置 Python 以及 Arduino IDE 的任务。无论你的系统是 Mac OS X、Linux 还是 Windows 系统,现在都已准备好迎接接下来的章节。在本章中,我们了解了 Arduino 的历史和构建模块。我们还学习了 Python 编程和 Arduino 语言的基础。现在,你准备好动手操作真实硬件,开始探索计算机与硬件的接口。在下一章中,我们将介绍接口的第一步,即使用串行接口将 Arduino 连接到计算机。

第二章:使用 Firmata 协议和 pySerial 库

在前一章中,你学习了 Python 编程语言和 Arduino 硬件平台的基础知识,以便开始使用。如果你直接阅读本章而没有阅读前一章,我们假设你对这些技术有一定的专业知识或工作经验。本章描述了两个将 Arduino 与 Python 连接所需的重要组件:

  • Arduino Firmata 协议
  • Python 的串行库名为pySerial

尽管 Firmata 协议对于将 Arduino 与 Python 接口很有用,但它也可以作为一个独立的工具来开发各种应用。

是时候拿出你的 Arduino 硬件并开始动手实践了。在本章的过程中,你需要一个 LED 灯、一个面包板、一个 1 千欧姆电阻以及你已经在上一章中使用过的组件,即 Arduino Uno 和 USB 线。

注意

如果你使用的是任何其他版本的 Arduino,你可以从arduino.cc/en/Guide/HomePage或位于forum.arduino.cc/的社区支持的 Arduino 论坛中获取更多信息。

连接 Arduino 板

如前一章所述,本书支持所有主要操作系统,本节将为你提供连接和配置 Arduino 板的步骤。在前一章中,我们使用了示例代码来开始使用 Arduino IDE。如果你没有按照前一章提供的信息成功与 Arduino 通信,请遵循本节提供的说明,在计算机和 Arduino 之间建立连接。首先,使用 USB 线将 Arduino 板连接到计算机的 USB 端口,并按照你的操作系统步骤进行操作。

Linux

如果你使用的是最新的 Ubuntu Linux 版本,一旦你连接 Arduino 板并打开 Arduino IDE,系统会要求你将自己的用户名添加到 dailout 组,如下面的截图所示。点击添加按钮并从系统中注销。你不需要重启计算机,更改即可生效。使用相同的用户名登录并打开 Arduino IDE。

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_02.jpg

如果你没有看到这个对话框,请检查是否可以在 Arduino IDE 的工具菜单中看到串行端口选项。可能是因为安装了其他程序已经将你的用户名添加到了 dailout 组。如果你没有对话框,且在串行端口没有选择项,请在终端中执行以下脚本,其中<username>是你的 Linux 用户名:

$ sudo usermod -a -G dialout <username>

此脚本将把您的用户名添加到拨出组,并且它也应该适用于其他 Linux 版本。在 Linux 中,Arduino 板通常连接为/dev/ttyACMx,其中x是整数值,取决于您的物理端口地址。如果您使用的是除 Ubuntu 以外的任何其他 Linux 发行版,您可能需要从 Arduino 网站上的 Linux 安装页面(playground.arduino.cc/Learning/Linux)检查与 Arduino 串行端口关联的正确组。

注意

对于 Fedora Linux 发行版,将uucplock组与dialout组合并,以控制串行端口:

$ sudo usermod -a -G uucp,dialout,lock <username>

Mac OS X

在 Mac OS X 中,当您通过串行端口连接 Arduino 时,操作系统将其配置为网络接口。在 OS X Mavericks 中,一旦 Arduino 板连接,从系统偏好设置中打开网络。应该会出现一个对话框,表明检测到新的网络接口。点击Thunderbolt Bridge确定,然后点击应用。以下截图显示了添加新网络接口的对话框:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_03.jpg

对于 OS X Lion 或更高版本,连接 Arduino 板时,将出现一个对话框,要求您添加新的网络接口。在这种情况下,您不需要导航到您的网络首选项。如果您看到状态为未连接并以红色突出显示的网络接口,请不要担心,因为它应该可以正常工作。

打开 Arduino IDE,从工具菜单导航到串行端口。您应该能看到类似于以下截图中的选项。Arduino 板连接的串行端口可能会根据您的 OS X 版本和连接的物理端口而有所不同。确保您为 USB 调制解调器选择一个tty接口。如以下截图所示,Arduino 板连接到串行端口/dev/tty.usbmodemfd121

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_04.jpg

Windows

如果您使用的是 Windows,Arduino 串行端口的配置非常简单。当您第一次连接 Arduino 板时,操作系统将自动安装必要的驱动程序。一旦此过程完成,从菜单栏中的串行端口选项中选择一个合适的 COM 端口。从主菜单中,导航到工具 | 串行端口并选择 COM 端口。

故障排除

即使按照前面提到的步骤操作,如果您仍然看不到以下截图所示的突出显示的串行端口选项,那么您可能遇到了问题。这可能有两个主要原因:串行端口被另一个程序使用,或者 Arduino USB 驱动程序没有正确安装。

如果有除 Arduino IDE 之外的其他程序正在使用特定的串行端口,请终止该程序并重新启动 Arduino IDE。有时在 Linux 中,brltty 库与 Arduino 串行接口冲突。请删除此库,注销并重新登录:

$ sudo apt-get remove brltty 

在 Windows 中,重新安装 Arduino IDE 也有效,因为这个过程会重新安装和配置 Arduino USB 驱动程序。

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_05.jpg

小贴士

Arduino 板一次只能由一个程序使用。在尝试使用 Arduino IDE 时,确保任何之前使用的程序或其他服务都没有使用串行端口或 Arduino,这一点非常重要。当我们开始在下节使用多个程序控制 Arduino 时,这个检查将变得非常重要。

假设你现在可以在 Arduino IDE 中选择串行端口,我们可以继续编译并将草图上传到您的 Arduino 板。Arduino IDE 预装了示例草图,您可以尝试使用它们。然而,在我们开始尝试复杂的示例之前,让我们先浏览下一节,该节解释了 Firmata 协议,并指导您逐步编译和上传草图。

介绍 Firmata 协议

在 Arduino 之前,基于微控制器的应用程序领域仅限于硬件程序员。Arduino 使来自其他软件领域的开发者和甚至非编码社区的开发者能够轻松地开发基于微控制器的硬件应用程序。Arduino 由一个简单的硬件设计组成,包括微控制器和 I/O 引脚,用于连接外部设备。如果能够编写一个 Arduino 草图,可以将微控制器和这些引脚的控制权转移到外部软件机制,那么这将减少每次修改上传 Arduino 草图的努力。这个过程可以通过开发这样的 Arduino 程序来完成,然后可以通过串行端口对其进行控制。存在一个名为 Firmata 的协议,它正是这样做的。

什么是 Firmata?

Firmata 是一种通用协议,允许微控制器与在计算机上托管的应用软件之间进行通信。任何能够进行串行通信的计算机主机上的软件都可以使用 Firmata 与微控制器通信。Firmata 使 Arduino 直接对软件提供完全访问权限,并消除了修改和上传 Arduino 草图的流程。

要使用 Firmata 协议,开发者可以一次性将支持该协议的草图上传到 Arduino 客户端。之后,开发者可以在主机计算机上编写自定义软件并执行复杂任务。该软件将通过串行端口向配备 Firmata 的 Arduino 板提供命令。他们可以在不中断 Arduino 硬件的情况下,不断更改主机计算机上的逻辑。

编写自定义 Arduino 草图的做法对于 Arduino 板需要本地执行任务的独立应用程序仍然有效。我们将在接下来的章节中探讨这两种选项。

注意

您可以从官方网站www.firmata.org了解更多关于 Firmata 协议及其最新版本的信息。

将 Firmata 草图上传到 Arduino 板

开始测试 Firmata 协议的最佳方式是将标准 Firmata 程序上传到 Arduino 板,并使用主机上的测试软件。在本节中,我们将演示一种将具有此标准 Firmata 程序的自定义 Arduino 草图上传到板的方法。这将成为将来上传任何草图时的默认方法。

实现 Firmata 协议需要最新的 Firmata 固件版本,您无需担心编写它。最新的 Arduino IDE 自带标准版本的 Firmata 固件,我们建议您使用最新的 IDE 以避免任何冲突。现在,按照以下步骤将程序上传到您的 Arduino 板:

  1. 如以下截图所示,通过在 Arduino IDE 中导航到文件 | 示例 | Firmata | StandardFirmata来打开StandardFirmata草图:https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_06.jpg
  2. 此操作将在新窗口中打开另一个草图簿,并在编辑器中加载StandardFirmata草图。不要修改草图中的任何内容,并继续执行下一节中描述的编译过程。重要的是不要修改代码,因为我们将要使用的测试软件与最新的未更改固件兼容。
  3. 一旦打开StandardFirmata草图,下一步就是为您的 Arduino 板编译它。在上一节中,我们已经将 Arduino 板连接到计算机并选择了正确的串行端口。然而,如果新的草图簿与之前的配置不同,请按照上一节的步骤操作,即选择适当的串行端口和 Arduino 板类型。
  4. 要编译当前草图,请点击以下截图所示的验证图标。您也可以通过导航到草图 | 验证/编译或点击Ctrl + R(如果您使用的是 Mac OS X,则为command + R)来编译它:https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_07.jpg编译过程应该没有错误完成,因为我们使用的是 IDE 自带的默认示例代码。现在,是时候将草图上传到板上了。请确保您已经连接了板。
  5. 按照以下截图所示,在工具栏中按下上传图标。此操作将上传编译后的代码到您的 Arduino 板:https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_08.jpg

完成后,你应该在 IDE 中看到上传完成的文本,如图下所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_09.jpg

你的 Arduino 板现在已安装了最新的 Firmata 固件,并等待来自计算机的请求。让我们继续到下一节,开始测试 Firmata 协议。

测试 Firmata 协议

在上一章中,我们使用了 13 号引脚上的板载 LED 来测试闪烁程序。这次,我们将使用外部 LED,帮助你开始使用 Arduino 板组装硬件组件。由于所有即将到来的练习和项目都将要求你使用面包板将硬件组件如传感器和执行器连接到 Arduino 板上,我们希望你开始获得实际操作这些组件的实践经验。

现在是时候使用我们在本章开头要求你获取的 LED 了。在我们开始接线 LED 之前,让我们首先了解它的物理原理。你获得的 LED 应该有两个引脚:一个短的和一个长的。短的引脚连接到 LED 的阴极,并且需要通过一个电阻连接到地。如图所示,我们使用一个 1 千欧姆的电阻将 LED 的阴极接地。连接到阳极的长引脚需要连接到 Arduino 板上的一个数字引脚。

如下图所示,我们将阳极连接到了数字引脚 13。查看图示并按照显示的接线方式接线。确保你已将 Arduino 板从主机计算机断开,以避免静电造成的任何损坏。

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_10.jpg

在这个例子中,我们将使用 LED 来测试 Firmata 协议的一些基本功能。我们已将 Firmata 代码上传到 Arduino 板,并准备好从主机计算机控制 LED。

注意

上述接线图是使用一个名为Fritzing的开源工具创建的。我们将在下一章全面介绍 Fritzing 工具,因为它将成为我们在实际物理接线之前创建接线图的标准软件。

使用 Firmata 与主机计算机通信有多种方式,例如使用支持的库在 Python 中编写自己的程序或使用预构建的测试软件。从下一节开始,我们将编写自己的程序来使用 Firmata,但在这个阶段,让我们使用一个免费工具进行测试。官方 Firmata 网站www.firmata.org还提供了测试工具,您可以从主页上的Firmata 测试程序部分下载。该网站为不同的操作系统提供了名为firmata_test的不同工具变体。按照以下步骤,您可以测试 Firmata 协议的实现:

  1. firmata_test程序的适当版本下载到您的计算机上。
  2. 现在,使用 USB 线将带有 LED 的 Arduino 板连接到主机计算机,并运行下载的firmata_test程序。您将能够在程序成功执行后看到一个空窗口。
  3. 如你在程序窗口中所见,你还有两列以及其他包含标签的列。程序中的第二列允许你选择适当引脚的角色。你可以指定数字引脚(在 Arduino Uno 的情况下,从 2 到 13)作为输入或输出。如以下截图所示,当你选择 2 号和 3 号引脚作为输入引脚时,你会在第三列看到。这是正确的,因为我们没有将这些引脚连接到任何输入。你可以通过更改多个引脚的角色和值来玩弄程序。https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_13.jpg由于我们已经将 LED 连接到数字引脚 13,所以在你玩弄其他引脚时,我们不会期望在板上出现任何物理变化。
  4. 现在,选择引脚 13 作为输出引脚并按下按钮。这将改变按钮的标签为,并且你会看到 LED 灯被点亮。通过执行此操作,我们已经将数字引脚 13 的逻辑更改为 1,即,这在引脚上相当于+5 伏特。这种电压足以点亮 LED。你可以通过再次点击按钮并将它切换到来将引脚 13 的级别改回 0。这将使电压回到 0 伏特。https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_14.jpg

一旦您选择了 Arduino 串行端口,程序将加载多个带有包含引脚编号标签的下拉框和按钮。您可以在下面的屏幕截图中看到,程序已加载了 12 个数字引脚(从引脚 2 到引脚 13)和 6 个模拟引脚(从引脚 14 到引脚 19)。由于我们使用 Arduino Uno 板进行我们的应用,测试程序只加载 Arduino Uno 板的部分引脚。如果您使用 Arduino Mega 或任何其他板,程序中显示的引脚数量将根据该特定 Arduino 板变体支持的引脚数量而定。https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_12.jpg

小贴士

在 Linux 上使用 firmata_test 程序在 Linux 平台上,您可能需要修改下载文件的属性并使其可执行。从同一目录中,在终端中运行以下命令使其可执行:

$ chmod +x firmata_test 

一旦您更改了权限,请使用以下命令从终端运行程序:

$ ./firmata_test 

如以下屏幕截图所示,从下拉菜单中选择适当的端口。请确保选择您用于上传 Arduino 草图相同的端口。https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_11.jpg

小贴士

在这一点上,请确保您的 Arduino IDE 没有使用相同的端口号连接到板。如我们之前提到的,串行接口一次只授予一个应用程序独家访问权限。

我们在这里使用的程序非常适合测试基础知识,但不能用来编写使用 Firmata 协议的复杂应用程序。在实际应用中,我们确实需要使用自定义代码来执行 Firmata 方法,这不仅包括切换 LED 状态,还包括实现智能逻辑和算法、与其他组件接口等。从下一节开始,我们将使用 Python 来处理这些应用。

开始使用 pySerial

在上一节中,你学习了 Firmata 协议。这是一个简单快捷的开始使用 Arduino 的方法。尽管 Firmata 协议可以帮助你在不修改 Arduino 草图的情况下从电脑上开发复杂的应用程序,但我们还没有准备好开始编写这些应用程序的代码。

编写这些复杂应用程序的第一步是在你的编程环境和 Arduino 之间通过串行端口提供一个接口。在这本书中,你将需要为每个我们开发的项目在 Python 解释器和 Arduino 之间建立连接。

编写自己的库,该库包括实现函数和规范以在串行协议上启用通信,是一个不方便且耗时的过程。我们将通过使用一个开源、维护良好的 Python 库pySerial来避免这种情况。

pySerial 库通过封装串行端口的访问来启用与 Arduino 的通信。此模块通过 Python 属性提供对串行端口设置的访问,并允许你通过解释器直接配置串行端口。pySerial 将成为 Python 和 Arduino 之间未来通信的桥梁。让我们从安装 pySerial 开始。

安装 pySerial

我们在第一章Python 和 Arduino 入门中安装了包管理器 Setuptools。如果你跳过了那一章并且对此不确定,那么请阅读该部分。如果你已经知道如何安装和配置 Python 库包,则可以跳过这些安装步骤。

从这个阶段开始,我们将只使用基于 pip 的安装命令,因为它们在第一章Python 和 Arduino 入门中描述的明显优势:

现在,为了检查 pySerial 是否成功安装,启动你的 Python 解释器,并使用以下命令导入 pySerial 库:

>>>import serial 

如果 Python 和 Setuptools 安装正确,那么在安装完成后,你应在命令行中看到以下输出:

.. Processing dependencies for pyserial Finished processing dependencies for pyserial 

这意味着你已经成功安装了 pySerial 库,并且可以进入下一部分。

打开终端或命令提示符,并执行以下命令:

> pip install pyserial 

Windows 操作系统不需要管理员级别的用户访问来执行命令,但在基于 Unix 的操作系统中,你应该有 root 权限来安装 Python 包,如下所示:

$ sudo pip install pyserial 

如果你想要从源代码安装 pySerial 库,请从 pypi.python.org/pypi/pyserial 下载存档,解压它,然后从 pySerial 目录中运行以下命令:

$ sudo python setup.py install 

玩转 pySerial 示例

你的 Arduino 板有来自上一个示例的 Firmata 草图 StandardFirmata。为了玩转 pySerial,我们不再使用 Firmata 协议。相反,我们将使用另一个简单的 Arduino 草图,该草图实现了可以在 Python 解释器上捕获的串行通信。

坚持不进行任何 Arduino 草图编码的承诺,让我们从 Arduino IDE 中选择一个示例草图:

  1. 如以下截图所示,导航到文件 | 示例 | 01. 基础 | DigitalReadSerialhttps://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_02_15.jpg
  2. 使用前面描述的方法编译并上传程序到 Arduino 板。选择你的 Arduino 连接的适当串行端口,并记下它。正如你在草图中所见,这段简单的 Arduino 代码以 9600 bps 的波特率通过串行端口传输数字引脚 2 的状态。
  3. 执行时,你应在 Python 解释器中看到重复的0值。按Ctrl + C来终止此代码。正如你所见,由于草图中的循环函数,Arduino 代码会持续发送消息。我们没有将任何东西连接到引脚 2,因此我们得到了状态0,即
  4. 如果你清楚自己在做什么,你可以将任何数字传感器连接到引脚 2,然后再次运行脚本以查看更改后的状态。

在不将 Arduino 板从计算机断开连接的情况下,打开 Python 解释器。然后,在 Python 解释器上执行以下命令。确保将/dev/ttyACM0替换为你之前记下的端口名称:

>>>import serial >>> s = serial.Serial('/dev/ttyACM0',9600)>>>whileTrue:print s.readline()

在前面的 Python 脚本中,serial.Serial方法用于接口和打开指定的串行端口,而readline()方法则从该接口读取每行,以\n结束,即换行符。

注意

换行符是一个特殊字符,表示文本行的结束。它也被称为行结束EOL)或换行+回车LF + CR)。了解更多关于换行符的信息,请访问en.wikipedia.org/wiki/Newline

连接 pySerial 和 Firmata

在 Firmata 部分,我们已经了解到使用 Firmata 协议而不是不断修改 Arduino 草图并上传它对于简单程序是多么有用。pySerial是一个简单的库,它通过串行端口在 Arduino 和 Python 之间提供桥梁,但它不支持 Firmata 协议。如前所述,Python 的最大好处可以用一句话来描述,“有库就能做到。”因此,存在一个名为pyFirmata的 Python 库,它是基于pySerial构建的,以支持 Firmata 协议。还有一些其他 Python 库也支持 Firmata,但我们将只在本章中关注pyFirmata。我们将在即将到来的各种项目中广泛使用这个库:

  1. 要使用 Firmata 协议进行通信,你需要再次上传StandardFirmata草图,就像我们在上传 Firmata 草图到 Arduino 板部分所做的那样。

同样,您也可以从提示符中读取引脚的状态:

>>> board.digital[pin].read()

您可以通过执行以下命令来关闭 LED。在这两个命令中,我们通过传递值1)或0)来设置数字引脚 13 的状态:

>>> board.digital[pin].write(0)

现在,您可以开始使用 Arduino 引脚进行实验了。通过执行以下命令来打开 LED:

>>> board.digital[pin].write(1)

在此之后,我们需要将端口与微控制器板类型关联:

>>> board = pyfirmata.Arduino(port)

在执行前面的脚本时,Arduino 上的两个 LED 会闪烁,因为 Python 解释器和板之间的通信链路正在建立。在测试 Firmata 协议部分,我们使用了一个预构建的程序来开关 LED。一旦 Arduino 板与 Python 解释器关联,这些功能可以直接从提示符中执行。

一旦上传了这个草图,打开 Python 解释器并执行以下脚本。此脚本将pyfirmata库导入到解释器中。它还定义了引脚号和端口。

>>>import pyfirmata >>> pin=13>>> port ='/dev/ttyACM0'

让我们从像安装其他 Python 包一样安装pyFirmata开始,使用 Setuptools:

$ sudo pin install pyfirmata 

在前面的章节中,当我们测试pySerial时,我们将DigitalSerialRead草图上传到了 Arduino 板。

如果我们将这个脚本与具有.py扩展名的可执行文件结合起来,我们就可以拥有一个可以直接运行的 Python 程序来控制 LED,而不是在终端上运行这些单个脚本。稍后,这个程序可以扩展以执行更复杂的功能,而无需编写或更改 Arduino 草图。

注意

虽然我们在 Python 提示符中运行单个脚本,但我们将在下一章中介绍创建 Python 可执行文件的过程。

摘要

通过引入 Firmata 库,我们避免了在本章中编写任何自定义 Arduino 草图。我们将在本书剩余部分继续这种做法,并且只有在需要时才会使用或创建自定义草图。在本章中,您通过与 Arduino 板交互使 LED 闪烁来与之交互,这是开始硬件项目的最简单方法。现在,是时候开始您的第一个项目了,我们也将使更多的 LED 闪烁。有人可能会问,如果我们已经做到了这一点,那么为什么还需要另一个项目来使 LED 闪烁呢?让我们来看看。

第三章。第一个项目 – 运动触发 LED

在上一章中,你学习了 Python-Arduino 接口的基础知识。我们通过一些练习来提供使用有用的 Arduino 协议 Firmata 和 Python 库的动手经验。现在,是时候进行你的第一个“Python + Arduino”项目了。

我们将从这个章节开始讨论项目目标和设计项目软件流程和硬件布局所需的组件。就像任何其他基于微控制器的硬件项目一样,你可以在 Arduino 上使用代码并实现项目的整个逻辑。然而,本书的目标是帮助你以这种方式利用 Python,从而简化并扩展你的硬件项目。尽管在接下来的章节中我们将使用 Python 程序辅助 Arduino 草图的双向方法,但我们希望让你熟悉这两种编程方式。由于这是你第一次构建硬件项目,本章为你提供了两种不同的编程方法:仅使用 Arduino 草图和使用带有 Firmata 协议的 Python 程序。包含 Arduino 草图的方法是为了让你获得与 Arduino 组件(如 I/O 引脚和串行通信)的完整体验。

运动触发 LED – 项目描述

当你开始学习任何编程语言时,在大多数情况下,你将编写代码来打印“Hello World!”。同时,在硬件项目中,大多数教程都是从帮助用户编写代码来闪烁 LED 开始的。这些练习或项目对于开发者开始使用语言是有用的,但大多数情况下,它们对现实世界的应用并没有任何重要性。然而,我们不想让你被一个复杂且复杂的项目压倒,这个项目可能需要你具备相当多的领域知识。

在上一章使用 Firmata 协议工作时,我们已经在 Arduino 板上闪烁了一个 LED。为了保持传统(拥有闪烁的 LED 作为第一个主要项目)并激发对项目的兴趣,让我们在闪烁 LED 项目中加入一些变化。在这个项目中,我们将闪烁两个不同的 LED,但不是以随机的方式执行这些动作,而是通过使用运动传感器测量的事件来执行。尽管由于这是你的第一个项目,项目的难度级别很简单,但它具有现实世界的应用价值,并且可以作为你日常生活中的简单应用。

项目目标

项目目标可以用一句话描述如下:“当检测到任何运动时,使用红色 LED 发出警报,并使用绿色 LED 显示正常状态。”在详细的目标列表中,你必须完成以下任务以满足提到的项目目标:

  • 使用被动红外PIR)传感器将环境中的任何运动检测为一个事件
  • 使用红色 LED 执行闪烁动作以表示此事件
  • 否则,使用绿色 LED 执行闪烁动作
  • 在执行动作后,保持系统循环并等待下一个事件

该项目可以作为 DIY 应用或作为其他项目的一部分进行实施,只需进行少量修改。以下是一些可以应用本项目概念的一些示例:

组件列表

在上一章中,我们仅使用 Arduino、Arduino USB 线和计算机进行编程。本项目所需的主要硬件组件是 PIR 运动传感器。您还需要额外的 LED。我们建议您使用与您已有的 LED 不同的颜色。所需组件的描述如下:

  • PIR 传感器:这些传感器被广泛用于 DIY 项目中的运动检测。它们体积小、价格低廉、功耗低,并且与 Arduino 等硬件平台兼容。PIR 传感器使用一对热释电传感器来检测红外辐射。如果没有运动,这些传感器的输出会相互抵消。任何环境中的运动都会通过这些热释电传感器产生不同水平的光辐射,差异将触发一个输出为HIGH(+5 伏特)的信号。我们将使用 SparkFun 销售的 PIR 传感器,您可以从www.sparkfun.com/products/8630获取它。PIR 传感器配备了所需的印刷电路板(PCB)。其范围为 20 英尺(6 米),对于该项目来说足够了。以下图片显示了 SparkFun 网站上可用的 PIR 传感器:https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_03_01.jpg来源:Sparkfun Inc.
  • LED 灯:我们建议您在项目中使用绿色和红色 LED 灯。如果它们不可用,您可以使用任何两种不同颜色的 LED 灯。
  • 电线、电阻和面包板:您需要一些电线和一个面包板来完成连接。作为最佳实践,至少要有三种不同颜色的电线连接器来表示电源、地线和信号。您还需要两个 220 欧姆和一个 10 千欧姆的拉电阻。
  • Arduino 板:Arduino Uno 板对于项目需求来说是足够的。你也可以使用 Arduino Mega 或任何其他 Arduino 板来完成这个项目。该项目只需要三个 I/O 引脚,而任何可用的 Arduino 板都配备了超过三个 I/O 引脚。
  • USB 线:你需要 USB 线来上传 Arduino 代码并与 Arduino 板进行串行通信。
  • 计算机:我们在前面的章节中已经为你的操作系统配置了一台装有 Python 和 Arduino IDE 的计算机。你将需要这台计算机来完成项目。确保你已经安装并配置了我们在前面的章节中安装和配置的所有软件组件。

软件流程设计

在开始任何硬件系统的工作之前,第一步是使用逻辑设计项目流程。我们建议你将项目绘制成流程图,以便更好地理解组件布局和代码流程。以下图显示了项目的流程,你可以看到一旦检测到运动,项目就会在循环中运行,并执行相应的 LED 动作:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_03_02.jpg

正如你所见,程序逻辑首先检测 PIR 传感器的状态,并根据该状态执行相应的动作。使用单个 Arduino 指令,你只能打开或关闭 LED。为了执行闪烁操作,我们需要在动作之间加入时间延迟,重复打开和关闭动作。我们还将插入延迟在每个连续循环的执行之间,以便 PIR 传感器的输出可以稳定下来。请注意,我们将使用相同的流程来编写两种编程方法的代码。

硬件系统设计

设计软件流程图有助于你编写程序,并协助你识别项目中的动作和事件。硬件系统设计的过程包括电路连接、原理图设计、仿真、验证和测试。这个设计过程提供了对项目及其硬件组件的详细了解。它还有助于对项目架构进行初步的验证和测试。在我们跳到这个项目的硬件设计过程之前,让我们先熟悉一下这些有用的工具。

介绍 Fritzing – 一款硬件原型设计软件

你不需要为这个项目设计硬件系统。总的来说,在这本书中,硬件系统设计将会提供,因为本书的主要焦点是编程而不是硬件设计。

如果你对手动设计或硬件组件的快速原型设计感兴趣,用于此目的的开源软件工具被称为Fritzing。你可以使用 Fritzing 来设计项目的原理图,并且可以从fritzing.org/download/获取。

Fritzing 是一个由设计师、艺术家和爱好者支持的社区支持的电子设计自动化软件项目。它允许您将您的硬件草图从纸上转换为软件电路图。Fritzing 还为您提供了一个从设计创建 PCB 布局的工具。Fritzing 广泛支持 Arduino 和其他流行的开源 DIY 硬件平台。您可以通过内置的示例项目探索 Fritzing。

安装并运行 Fritzing。以下截图显示了打开 Fritzing 后显示的默认项目之一:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_03_03.jpg

如您所见,一个包含虚拟硬件组件的工具箱位于打开窗口的右侧。位于中心的主体编辑空间允许用户从工具箱中拖放组件,并允许用户完成这些组件之间的连接。您可以在fritzing.org/learning/了解更多 Fritzing 提供的功能,并查看一些动手教程。

使用面包板

一旦您熟悉了 Fritzing,您就有灵活性来创建自己的电路,或者您始终可以使用书中提供的 Fritzing 文件。然而,还有一个挑战,那就是将您的虚拟电路移植到物理电路。电子项目中使用的最基本组件之一是允许您实现连接并构建物理电路的面包板

面包板内含有智能组织的金属排,这些金属排隐藏在带有塑料孔的组件下面。这个组件帮助用户在不进行任何焊接工作的前提下连接电线。通过这些孔插入和移除电线或电子组件非常容易。以下图显示了带有几个组件和一些电线连接的小型面包板:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_03_09.jpg

注意

learn.sparkfun.com/tutorials/how-to-use-a-breadboard了解更多关于面包板和使用它们的教程。

面包板主要有两种类型的连接条:端子条和电源轨。如图所示,端子条是电学上短接的孔的垂直列。简单来说,一旦你将任何组件连接到端子条中的一列,该组件就会与该列中的每个孔电学连接。端子条的列之间由双列直插式封装DIP)支撑间隙分隔。(DIP 是电子组件的常见封装。)在同一列中,DIP 支撑间隙上方和下方的端子条在电学上是独立的。同时,电源轨在整个面包板的一行中水平短接。电源轨主要用于连接电源的正极和地,因此它可以轻松地分配到所有组件。

注意

面包板的历史

在电子的早期年代,人们使用真正的面包板(用于切面包的)来用钉子和电线连接他们的大型组件。随着电子组件开始变得更小,组装电路的板也变得更好。这个术语在这次演变中保留了下来,我们仍然称现代的板为面包板。如果你感兴趣,可以查看www.instructables.com/id/Use-a-real-Bread-Board-for-prototyping-your-circui/,它提供了使用原始面包板组装电路的说明。

设计硬件原型

是时候收集前面提到的硬件组件并开始构建系统了。下一图显示了使用 Fritzing 开发的项目的电路图。如果你有电路组装的先前经验,请继续按照图中的显示连接组件:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_03_04.jpg

如果这是你第一次使用传感器和面包板,请按照以下步骤完成电路组装:

  1. 将 Arduino 的 VCC(+5V)和地连接到面包板。
  2. 将红色 LED 的正极(长引脚)连接到 Arduino 板的数字引脚 12。将红色 LED 的负极(短引脚)通过 220 欧姆电阻器连接到地。
  3. 将绿色 LED 的正极(长引脚)连接到 Arduino 板的数字引脚 13。将绿色 LED 的负极(短引脚)通过 220 欧姆电阻器连接到地。
  4. 将 PIR 传感器的 VDD 连接到面包板上的 VCC。使用相同的线色来表示相同的连接类别。这将极大地帮助电路的故障排除。
  5. 将 PIR 传感器的信号(中间引脚)通过 10 千欧姆的上拉电阻器连接到 Arduino 板的数字引脚 7。

大多数专家更喜欢原理图而不是我们之前使用的原型图。当你使用与原型图中的确切组件兼容的组件时,原理图非常有用。以下是我们之前设计的电子电路的原理图。此图也是使用 Fritzing 获得的:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_03_05.jpg

你的系统现在已准备好运行 Arduino 程序。由于我们将使用相同的硬件进行编程方法,除非你遇到问题,否则你几乎完成了电子工作。为了确保一切连接得完美,让我们在下一节检查这些连接。

注意

注意,上拉电阻被用来确保 PIR 传感器的输出信号达到预期的逻辑电平。

测试硬件连接

一旦电路连接完成,你就可以直接进入编程部分。作为一个最佳实践,我们建议你验证电路连接并检查传感器的状态。我们假设你的 Arduino 板已经配备了我们在上一章中讨论的StandardFirmata草图。否则,请参考上一章,并将StandardFirmata草图上传到你的 Arduino 板。

验证我们的电路实现的最佳方式是使用我们在上一章中使用的 Firmata 测试程序。根据项目设置,PIR 传感器向 Arduino 引脚 7 提供事件输入。在测试程序中,将引脚 7 的类型更改为输入,并在传感器上方挥动手,你应该能够看到引脚的状态为,如以下截图所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_03_06.jpg

通过将引脚 12 和 13 设置为输出引脚并切换按钮来设置引脚的状态,检查 LED 的连接。如果你在切换按钮时看到 LED 闪烁,那么你的连接工作得非常完美。

如果你无法成功执行这些检查,请验证并重复设计步骤。

方法 1 – 使用独立的 Arduino 草图

正如我们在前面的章节中讨论的,一个项目可以通过创建特定于项目的原生 Arduino 代码或使用 Python-Arduino 混合方法来实现。

原生的 Arduino 草图在不需要与计算机系统进行通信或通信可忽略的情况下非常有用。尽管这种独立项目在没有串行连接的情况下可以持续运行,但更新和上传 Arduino 草图进行微小修改是困难的。

如果你查看这个项目的各种应用,你会注意到其中只有少数需要将项目实现为一个仅检测运动并闪烁 LED 的独立系统。这种类型的系统可以通过一个简单的 Arduino 草图轻松实现。

项目设置

在我们继续项目之前,请确保您已准备好以下事项:

  • 硬件组件已设置并正常运行
  • 您的 Arduino 通过 USB 线连接到计算机
  • 您的计算机上安装了 Arduino IDE,您可以通过 IDE 访问连接的 Arduino 板

Arduino 草图

本节描述了项目的 Arduino 代码。在我们逐步描述代码之前,让我们首先遵循以下步骤来运行项目:

  1. 打开 Arduino IDE。
  2. 文件菜单中打开一个新的草图簿。
  3. 编译并将草图上传到 Arduino 板。

将以下 Arduino 代码复制到草图并保存:

int pirPin =7;//Pin number for PIR sensor int redLedPin =12;//Pin number for Red LED int greenLedPin =13;//Pin number for Green LED void setup(){ Serial.begin(9600); pinMode(pirPin, INPUT); pinMode(redLedPin, OUTPUT); pinMode(greenLedPin, OUTPUT);} void loop(){int pirVal = digitalRead(pirPin);if(pirVal == LOW){//was motion detected blinkLED(greenLedPin,"No motion detected.");}else{ blinkLED(redLedPin,"Motion detected.");}}// Function which blinks LED at specified pin number void blinkLED(int pin, String message){ digitalWrite(pin,HIGH); Serial.println(message); delay(1000); digitalWrite(pin,LOW); delay(2000);}

现在,您已经使用第一种编程方法完成了项目,并且已成功将其部署到硬件上。它应该正在运行设计的算法以检测运动事件并执行闪烁动作。

由于您的项目运行正常,现在是时候理解代码了。像任何其他 Arduino 程序一样,代码有两个强制性的函数:setup()loop()。它还有一个自定义函数blinkLED(),用于执行稍后解释的特定动作。

setup()函数

如您在前面的代码片段中所见,我们在程序开始时将变量分配给了 Arduino 引脚。在setup()函数中,我们配置了这些变量,使其定义为输入或输出引脚:

pinMode(pirPin, INPUT); pinMode(redLedPin, OUTPUT); pinMode(greenLedPin, OUTPUT);

在这里,pirPinredLedPingreenLedPin分别是数字引脚 7、12 和 13。在同一个函数中,我们还配置了 Arduino 板以在 9600 bps 的波特率下提供串行连接性:

Serial.begin(9600);

loop()函数

loop()函数中,我们反复监控来自pirPin数字引脚的输入以检测运动。当检测到运动时,该引脚的输出为HIGH,否则为LOW。此逻辑通过简单的if-else语句实现。当满足此条件时,函数调用用户定义的函数blinkLED(),以对 LED 执行适当的动作。

用户定义的函数是任何编程语言的一个重要方面。让我们花些时间学习如何创建自己的 Arduino 函数以执行各种动作。

使用自定义 Arduino 函数进行工作

当一段代码需要重复执行以执行相同动作时,会使用函数。用户可以创建自定义函数来组织代码或执行重复动作。为了成功使用自定义函数,用户需要从强制性的 Arduino 函数(如loop()setup()或任何导致这些强制性函数的其他函数)中调用它们:

return-type function_name (parameters){# Action to be performed Action_1; Action_2; Return expression;}

在先前的 Arduino 函数框架中,return-type可以是任何 Arduino 数据类型,如intfloatstring等,或者如果代码不返回任何内容,则为void。以下是我们项目代码中使用的自定义函数:

void blinkLED(int pin, String message){ digitalWrite(pin,HIGH); Serial.println(message); delay(1000); digitalWrite(pin,LOW); delay(2000);}

在我们的项目中,当从loop()函数调用blinkLED()函数时,它不会返回任何值。因此,return-typevoid。在调用函数时,我们传递引脚号和消息作为参数:

blinkLED(greenLedPin,"No motion detected.");

这些参数随后被blinkLED()函数用于执行操作(在串行端口上写入消息并设置 LED 状态)。此函数还通过使用delay()函数引入延迟来执行闪烁动作。

测试

我们在测试硬件连接部分使用手动输入通过 Firmata 测试程序验证了设计的系统。由于我们现在已经实现了软件设计,我们需要验证项目是否能够自主且重复地执行客观任务。

将 USB 端口连接到计算机后,通过导航到工具 | 串行监视器或按Ctrl + Shift + M打开 Arduino IDE 中的串行监视工具。你应该开始在串行监视器窗口看到类似于以下截图的消息:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_03_07.jpg

当编写blinkLED()函数以执行操作时,我们包括了一个通过串行端口写入字符串的动作。将你的手在 PIR 传感器上方移动,以便 PIR 传感器可以检测到运动。此事件应触发系统闪烁红色 LED 并在串行监视器上显示字符串Motion detected。一旦你保持稳定并避免任何运动一段时间,你将能够看到绿色 LED 闪烁,直到通过 PIR 传感器检测到下一次运动。

故障排除

故障排除是一个重要的过程,如果出现问题,以下是一些示例问题和相应的故障排除步骤:

  • 串行输出正确,但没有闪烁的 LED:
    • 检查面包板上的 LED 连接
  • LED 闪烁,但没有串行输出:
    • 检查串行监视器配置的端口
    • 检查串行监视器中的波特率是否正确(9600 bps)
  • 没有串行输出和没有闪烁的 LED:
    • 检查 PIR 传感器连接并确保你从 PIR 传感器获得信号
    • 检查你的 Arduino 代码
    • 检查电源和地线连接

方法 2 – 使用 Python 和 Firmata

在上一章中,我们讨论了使用由 Firmata 辅助的 Python 编程相对于使用原生 Arduino 脚本的优点。基于 Python 的编程方法在进行任何算法或参数更改时提供了切实可行的体验。在本节中,我们将探讨这些优点,并学习重要的 Python 编程范式。

项目设置

在我们继续进行 Python 编程之前,让我们确保你已经完成了以下操作:

  • 确保硬件组件已按照系统设计描述设置好
  • 使用 USB 线将 Arduino 连接到你的计算机
  • StandardFirmata草图重新上传到 Arduino
  • 确保您的计算机上已安装 Python 和 Python 包(pySerialpyFirmata
  • 获取一个文本编辑器来编写 Python 代码

使用 Python 可执行文件

在前面的章节中,我们使用交互式 Python 解释器探索了 Python 编程。然而,当处理大型项目时,很难继续使用 Python 交互式解释器进行重复性任务。与其他编程语言一样,首选的方法是创建 Python 可执行文件并在终端中运行它们。

Python 可执行文件带有 .py 扩展名,格式为纯文本。任何文本编辑器都可以用来创建这些文件。常用的编辑器包括 Notepad++、nano、vi 等。此列表还包括与 Python 安装文件一起提供的默认编辑器 IDLE。您可以使用您选择的编辑器,但请确保将文件保存为 .py 扩展名。让我们将以下代码行复制到一个新文件中,并将其保存为 test.py

#!/usr/bin/python a ="Python" b ="Programming"print a +" "+ b 

要运行此文件,请在保存 test.py 文件的终端上执行以下命令:

$ python test.py 

您应该在终端上看到打印的文本 Python Programming。如您所见,文件以 #!/usr/bin/python 开头,这是默认的 Python 安装位置。通过在您的 Python 代码中添加此行,您可以直接从终端执行 Python 文件。在基于 Unix 的操作系统中,您需要通过以下命令使 test.py 文件可执行:

$ chmod +x test.py 

现在,由于您的文件是可执行的,您可以直接使用以下命令运行该文件:

$./test.py 

注意

对于基于 Unix 的操作系统,提供 Python 解释器位置的另一种方法是使用以下代码行,而不是我们之前使用的代码行:

#!/usr/bin/env python

在 Windows 操作系统中,Python 文件由于 .py 扩展名而自动成为可执行文件。您只需双击并打开程序文件即可运行程序。

Python 代码

如您现在所知,如何创建和运行 Python 代码,让我们创建一个新的 Python 文件,并使用以下代码片段运行它。请确保根据前一章所述,根据您的操作系统更改 port 变量的值:

#!/usr/bin/python# Import required librariesimport pyfirmata from time import sleep # Define custom function to perform Blink actiondefblinkLED(pin, message):print message board.digital[pin].write(1) sleep(1) board.digital[pin].write(0) sleep(1)# Associate port and board with pyFirmata port ='/dev/ttyACM0' board = pyfirmata.Arduino(port)# Use iterator thread to avoid buffer overflow it = pyfirmata.util.Iterator(board) it.start()# Define pins  pirPin = board.get_pin('d:7:i') redPin =12 greenPin =13# Check for PIR sensor inputwhileTrue:# Ignore case when receiving None value from pin value = pirPin.read()while value isNone:passif value isTrue:# Perform Blink using custom function blinkLED(redPin,"Motion Detected")else:# Perform Blink using custom function blinkLED(greenPin,"No motion Detected")# Release the board board.exit()

您已成功使用 Python 创建并执行了您的第一个 Arduino 项目。此代码中有两个主要的编程组件:pyFirmata 方法以及执行闪烁动作的 Python 函数。程序会重复检测运动事件并执行闪烁动作。在前一节中,我们通过使用默认的 Arduino 函数 loop() 解决了这个问题。在此方法中,我们实现了 while 语句以使程序在代码被用户手动终止前保持循环。您可以使用键盘组合 Ctrl + C 终止代码。

使用 pyFirmata 方法

作为使用 Arduino 板和 Firmata 协议的一部分,你必须首先将 Arduino 板初始化为变量。允许用户将板分配给 Python 变量的 pyFirmata 方法如下:

board = pyfirmata.Arduino(port)

一旦变量的值被分配,你可以执行各种操作,例如使用该变量读取引脚或向引脚发送信号。要分配引脚的角色,使用 get_pin() 方法。在以下代码行中,d 代表数字引脚,7 是引脚号,i 代表该引脚类型是输入引脚:

pirPin = board.get_pin('d:7:i')

一旦将引脚及其角色分配给变量,该变量就可以用来读取或写入引脚上的值:

Value = pirPin.read()

可以直接将数据写入特定的引脚,如下面的代码所示:

board.digital[pin].write(1)

在这里,write(1) 方法向引脚发送 HIGH 信号。我们将在接下来的章节中学习更多的 pyFirmata 方法。

使用 Python 函数

Python 函数以 def 关键字开头,后跟函数名和输入参数或参数。函数定义以冒号(:)结束,之后进行缩进。return 语句终止函数。它还将表达式传递到函数被调用的位置。如果没有表达式,return 语句被认为是传递返回值 None

deffunction_name(parameters): action_1 action_2 return[expression]

之前提到的框架可以用来创建自定义函数以执行重复任务。在我们的项目中,我们有 blinkLED(pin, message) 函数来执行闪烁 LED 操作。此函数向指定的数字引脚发送 1 (HIGH) 和 0 (LOW) 值,同时在终端打印 message。它还引入延迟来模拟闪烁动作:

defblinkLED(pin, message):print message board.digital[pin].write(1) sleep(1) board.digital[pin].write(0) sleep(1)

测试

你可以在终端上运行 Python 代码后立即开始测试项目。如果一切按设计进行,你应该能在终端看到以下输出:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_03_08.jpg

当 PIR 传感器检测到任何运动时,你应该能在终端上看到 Motion Detected 字符串。如果你在输出中找到任何异常行为,请检查 Python 代码。

使用 Python 的好处是,如更改闪烁速度或交换 LED 角色等小修改,只需更改 Python 代码即可完成,无需处理 Arduino 或电路。

故障排除

当你运行项目时,你可能需要解决以下可能的问题:

  • 串行输出正确,但没有闪烁的 LED:
    • 检查面包板上的 LED 连接
  • LED 闪烁,但没有串行输出:
    • 检查你是否已成功将标准 Firmata 草图安装到板上
  • 如果没有串行输出和闪烁的 LED:
    • 检查是否有除 Python 之外的其他程序正在使用串行端口。关闭可能正在使用该串行端口的任何程序,包括 Arduino IDE。
    • 验证所有电路连接。
    • 确保在 Python 代码中指定的端口号是正确的。

摘要

在本章中你学习到的两种编程方法中,仅使用 Arduino 脚本的这种方法代表了传统的微控制器编程范式。虽然这种方法实现起来简单,但它缺乏通过 Python-Arduino 接口获得的广泛性。尽管从现在开始的所有项目都将使用广泛的 Arduino 编程,但练习和项目将以 Python-Arduino 接口作为主要的编程方式。

从下一章开始,我们将探索可以扩展基于 Arduino 硬件项目可用性的 Python 编程的额外方面,同时将编程难度保持在最低。我们将从 Python-Arduino 原型设计开始,然后创建用于用户交互的图形界面,在完成第二个项目,该项目利用了这些概念之前停止。

第四章:深入 Python-Arduino 原型设计

在完成第一个项目后,你成功开始了 Python-Arduino 接口。我们还通过数字引脚将多个硬件组件(即运动传感器和 LED)与 Arduino 接口。在项目过程中,你通过使用简单的 Python 方法学习了更多关于 Firmata 协议的知识,这些方法帮助你建立 Arduino 板与 Python 程序之间的连接。当你处理复杂项目时,你需要比基本方法更多的东西来实现项目及其相关电子组件所需的不同功能。本章旨在为你提供全面的接口体验,以便你从下一章开始着手解决难题。我们描述了 Python-Arduino 和 Arduino 到组件级别的各种接口协议。本章还包括了这些协议的实践示例,包括适当的代码和电路图。在本章中,我们将涵盖以下主要主题:

  • 原型设计简介
  • 详细描述将 Arduino 功能导入 Python 的pyFirmata方法的介绍
  • 使用 Firmata 进行 Python-Arduino 接口的示例,包括电位计、蜂鸣器、直流电机和伺服电机等基本电子元件
  • 互连集成电路I2C)协议简介及 I2C 组件(如温度传感器(TMP102)和光传感器(BH1750))的原型设计示例

原型设计

就让我们暂时回顾一下上一章中我们构建的项目。这个项目目标非常简单,我们能够相当轻松地完成它。然而,这个项目显然还没有准备好成为一款消费产品,因为它缺乏显著的功能,最重要的是,它不是一个可以重复生产的稳健产品。关于你当前的项目,你可以知道的是,它是一个个人使用的 DIY 项目,或者只是一个可以进一步开发成为优秀产品的模型。

现在,如果你打算开发一款商业产品或者一个真正稳健且可扩展的 DIY 项目,你必须考虑首先制作一个模型。在这个阶段,你需要设想产品所需的功能以及部署这些功能所需的组件数量。原型设计基本上是一种快速创建你设想中的想法的工作模型的方法,在将其开发成完整功能的项目或产品之前。在原型设计过程中开发的证明概念原型让你能够确定你想法的可行性,在某些情况下,它还帮助你探索项目的潜力。原型设计或功能模型制作过程对于任何行业都是至关重要的,而不仅仅是电子行业。

在电子领域,原型设计可以在将组件与计算机接口的第一个阶段使用,而不是直接投入大量资源进行原理图设计、PCB 制造和开发完整的代码库。这一阶段有助于你识别电路设计中的主要缺陷,并检查所选组件的相互兼容性。

幸运的是,Arduino 及其周围的现有软件支持极大地简化了电子原型设计。在接下来的章节中,我们将介绍各种辅助函数和接口练习,以帮助你进行自己的项目。这些示例或模板设计得如此之好,以至于它们可以用作更大项目的蓝图。

在深入研究这些原型设计示例之前,让我们了解我们将在本章中探索的两个不同的接口抽象:

  • 将 Arduino 与 Python 接口:我们已经学习了使用 Firmata 协议进行 Python-Arduino 接口的最简单方法。在 Arduino 板上,Firmata 协议是通过 StandardFirmata 固件实现的,而在 Python 端,我们使用了 Firmata 库,即 pyFirmatapyMata。另一种 Python-Arduino 接口方法包括在 Python 程序中使用自定义 Arduino 脚本和 pySerial 库的简单但非标准的串行命令。使用计算机网络在 Python 和 Arduino 之间建立通信也是可能的,这在本书的后续部分将进行介绍。
  • 将电子组件与 Arduino 接口:第二个接口抽象与 Arduino 和物理组件相关。正如我们已经做的那样,各种电子组件可以通过数字或模拟引脚简单地与 Arduino 板接口。这些组件处理数字或模拟信号。Arduino 板上的一些数字引脚支持特定硬件设备的 PWM 通信。其他替代接口方法包括 I2C 和 串行外设接口SPI)通信。I2C 方法在本章的最后部分进行了全面解释。

使用 pyFirmata 方法

pyFirmata 包提供了有用的方法来弥合 Python 和 Arduino 的 Firmata 协议之间的差距。尽管这些方法是用具体的例子描述的,但你也可以以各种不同的方式使用它们。本节还详细描述了一些在先前项目中未使用的方法,并列出了缺失的功能。

设置 Arduino 板

要在 Python 程序中使用pyFirmata设置你的 Arduino 板,你需要特别遵循我们已覆盖的步骤。我们将整个设置过程所需的代码分散到每个步骤中的小代码片段中。在编写代码时,你必须仔细使用适合你应用场景的代码片段。你总是可以参考包含完整代码的示例 Python 文件。在我们继续之前,首先确保你的 Arduino 板安装了最新版本的StandardFirmata程序,并且已经连接到你的电脑:

Arduino 板与pyFirmata之间的同步需要一些时间。在先前的赋值和下一组指令之间添加睡眠时间可以帮助避免与串行端口缓冲相关的问题。添加睡眠时间最简单的方法是使用内置的 Python 方法sleep(time)

from time import sleep sleep(1)

sleep()方法接受秒作为参数,可以使用浮点数来提供特定的睡眠时间。例如,对于 200 毫秒,将是sleep(0.2)

一旦你导入了 Arduino 类并将端口分配给一个变量对象,就是时候将 Arduino 与pyFirmata结合并关联到另一个变量上了:

board = Arduino(port)

同样,对于 Arduino Mega,使用这个:

board = ArduinoMega(port)

在我们开始执行与处理引脚相关的任何方法之前,你需要正确设置 Arduino 板。要执行此任务,我们首先需要识别 Arduino 板连接的 USB 端口,并将此位置以字符串对象的形式分配给一个变量。对于 Mac OS X,端口字符串应大致如下所示:

port ='/dev/cu.usbmodemfa1331'

对于 Windows 系统,使用以下字符串结构:

port ='COM3'

在 Linux 操作系统的案例中,使用以下代码行:

port ='/dev/ttyACM0'

端口的位置可能会根据你的电脑配置而有所不同。你可以通过 Arduino IDE,如第二章中所述,使用以下方法来识别你的 Arduino USB 端口的正确位置:使用 Firmata 协议和 pySerial 库

根据所使用的 Arduino 板,首先将适当的pyFirmata类导入到 Python 代码中。目前,内置的pyFirmata类仅支持 Arduino Uno 和 Arduino Mega 板:

from pyfirmata import Arduino 

在 Arduino Mega 的情况下,使用以下代码行:

from pyfirmata import ArduinoMega 

到目前为止,你已经成功使用pyFirmata将 Arduino Uno 或 Arduino Mega 板同步到电脑上。如果你想使用 Arduino 板的其它变体(除了 Arduino Uno 或 Arduino Mega)怎么办?

由于您之前已经同步了 Arduino 板,请使用setup_layout(layout)方法修改板的布局:

board.setup_layout(nano)

此命令将修改同步的 Arduino 板的默认布局为 Arduino Nano 布局或任何其他您已定制的字典对象变体。

对于您的 Arduino 板变体,您必须首先创建一个自定义字典对象。要创建此对象,您需要了解您的板硬件布局。例如,Arduino Nano 板的布局类似于常规 Arduino 板,但它有八个而不是六个模拟端口。因此,前面的字典对象可以定制如下:

nano ={'digital':tuple(x for x inrange(14)),'analog':tuple(x for x inrange(8)),'pwm':(3,5,6,9,10,11),'use_ports':True,'disabled':(0,1)# Rx, Tx, Crystal}

pyFirmata中,任何板布局都被定义为字典对象。以下是一个 Arduino 板字典对象的示例:

arduino ={'digital':tuple(x for x inrange(14)),'analog':tuple(x for x inrange(6)),'pwm':(3,5,6,9,10,11),'use_ports':True,'disabled':(0,1)# Rx, Tx, Crystal}

配置 Arduino 引脚

一旦您的 Arduino 板同步完成,就是时候配置将要作为程序一部分使用的数字和模拟引脚了。Arduino 板具有数字 I/O 引脚和模拟输入引脚,可以用于执行各种操作。正如我们所知,其中一些数字引脚也具备 PWM 功能。

直接方法

在我们开始向这些引脚写入或读取任何数据之前,我们必须首先将这些引脚的模式分配好。在上一章中我们使用的基于 Arduino 草图的方法中,我们使用了pinMode函数,即pinMode(11, INPUT)进行此操作。同样,在pyFirmata中,此分配操作是通过在板对象上使用mode方法来执行的,如下面的代码片段所示:

from pyfirmata import Arduino from pyfirmata import INPUT, OUTPUT, PWM # Setting up Arduino board port ='/dev/cu.usbmodemfa1331' board = Arduino(port)# Assigning modes to digital pins board.digital[13].mode = OUTPUT board.analog[0].mode = INPUT 

pyFirmata库包括用于INPUTOUTPUT模式的类,在使用之前需要导入。前面的示例展示了将数字引脚 13 委托为输出,将模拟引脚 0 委托为输入。模式方法是在使用digital[]analog[]数组索引分配配置的 Arduino 板变量上执行的。

pyFirmata库还支持PWMSERVO等附加模式。PWM模式用于从数字引脚获取模拟结果,而SERVO模式帮助数字引脚设置轴的角度在 0 到 180 度之间。PWMSERVO模式将在本章后面的详细示例中解释。如果您使用这些模式中的任何一个,请从pyFirmata库导入相应的类。一旦从pyFirmata包中导入了这些类,就可以使用以下代码行为适当的引脚分配模式:

board.digital[3].mode = PWM board.digital[10].mode = SERVO 

注意

在电子学中,PWM 是一种信号调制技术,广泛用于向组件提供受控的功率。在处理数字信号时,PWM 技术通过利用方波和控制信号宽度来获得模拟结果。

如我们所知,Arduino 板的数字引脚只能有两种状态,5V(高)和 0V(低)。通过控制高和低之间的切换模式,可以生成方波脉冲,从而产生脉冲。通过改变这些脉冲的宽度,可以模拟 0V 到 5V 之间的任何电压。如图所示,我们有一个占空比为 25%的方波。这意味着在占空期的这段时间内,我们正在模拟 0.25 * 5V = 1.25V:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_04_06.jpg

Arduino 语言使用analogWrite()函数支持 PWM,其中 0V 到 5V 之间的电压范围以 0 到 255 之间的线性比例缩放。例如,50%的占空比(模拟 2.5V)转换为值 127,可以在 Arduino 中编码为analogWrite(13,127)。在这里,数字13代表支持 PWM 的 Arduino Uno 板上的数字引脚。同样,20%的占空比(1V)转换为analogWrite(13,64)

分配引脚模式

配置引脚的直接方法主要用于单行执行调用。在一个包含大量代码和复杂逻辑的项目中,将具有特定功能的引脚分配给变量对象是非常方便的。使用这样的赋值,你可以在程序中利用分配的变量执行各种操作,而不是每次需要使用该引脚时都调用直接方法。在pyFirmata中,可以使用get_pin(pin_def)方法执行此赋值:

from pyfirmata import Arduino port ='/dev/cu.usbmodemfa1311' board = Arduino(port)# pin mode assignment ledPin = board.get_pin('d:13:o')

get_pin()方法允许你使用pin_def字符串参数('d:13:o')分配引脚模式。pin_def的三个组成部分是引脚类型、引脚号和引脚模式,由冒号(:)运算符分隔。引脚类型(模拟和数字)分别用ad表示。get_pin()方法支持三种模式,i表示输入,o表示输出,p表示 PWM。在之前的代码示例中,'d:13:o'指定数字引脚 13 为输出。在另一个示例中,如果你想将模拟引脚 1 设置为输入,参数字符串将是'a:1:i'

操作引脚

现在你已经配置了 Arduino 引脚,是时候开始使用它们执行操作了。在操作引脚时,支持两种不同类型的方法:报告方法和 I/O 操作方法。

报告数据

当引脚在程序中配置为模拟输入引脚时,它们开始向串行端口发送输入值。如果程序不利用这些传入的数据,数据将开始在串行端口缓冲,并迅速溢出。pyFirmata库提供了报告和迭代方法来处理这种现象。

使用enable_reporting()方法将输入引脚设置为开始报告。在执行引脚的读取操作之前,需要使用此方法:

board.analog[3].enable_reporting()

读取操作完成后,可以将引脚设置为禁用报告:

board.analog[3].disable_reporting()

在前面的例子中,我们假设你已经设置了 Arduino 板并配置了模拟引脚 3 的模式为 INPUT

pyFirmata 库还提供了 Iterator() 类来读取和处理串行端口上的数据。当使用模拟引脚时,我们建议你在主循环中启动一个迭代器线程来更新引脚值为最新值。如果不使用迭代器方法,缓冲数据可能会溢出你的串行端口。这个类在 pyFirmata 包的 util 模块中定义,并在代码中使用之前需要导入:

from pyfirmata import Arduino, util # Setting up the Arduino board port ='COM3' board = Arduino(port) sleep(5)# Start Iterator to avoid serial overflow it = util.Iterator(board) it.start()

手动操作

由于我们已经配置了 Arduino 引脚到合适的模式和它们的报告特性,我们可以开始监控它们。pyFirmata 库为配置的引脚提供了 write()read() 方法。

write() 方法

write() 方法用于向引脚写入一个值。如果引脚的模式设置为 OUTPUT,则值参数是一个布尔值,即 01

board.digital[pin].mode = OUTPUT board.digital[pin].write(1)

如果你使用了替代的引脚模式赋值方法,你可以按照以下方式使用 write() 方法:

ledPin = board.get_pin('d:13:o') ledPin.write(1)

在 PWM 信号的情况下,Arduino 接受一个介于 0 和 255 之间的值,该值表示 0 到 100 百分比之间的占空期长度。pyFirmata 库提供了一个简化的方法来处理 PWM 值,而不是介于 0 和 255 之间的值,你可以提供一个介于 0 和 1.0 之间的浮点值。例如,如果你想有一个 50 百分比的占空期(2.5V 的模拟值),你可以使用 write() 方法指定 0.5pyFirmata 库将负责转换并发送适当的值,即 127,通过 Firmata 协议发送到 Arduino 板:

board.digital[pin].mode = PWM board.digital[pin].write(0.5)

类似地,对于间接赋值方法,你可以使用一些类似于以下代码片段的代码:

pwmPin = board.get_pin('d:13:p') pwmPin.write(0.5)

如果你使用的是 SERVO 模式,你需要提供介于 0 和 180 度之间的值。不幸的是,SERVO 模式仅适用于直接赋值引脚,并且将来将适用于间接赋值:

board.digital[pin].mode = SERVO board.digital[pin].write(90)
read() 方法

read() 方法在指定的 Arduino 引脚上提供一个输出值。当使用 Iterator() 类时,使用此方法接收到的值是串行端口上最新更新的值。当你读取一个数字引脚时,你可以得到两个输入之一,HIGHLOW,这将在 Python 中转换为 10

board.digital[pin].read()

Arduino 的模拟引脚将 0 到 +5V 之间的输入电压线性转换为 0 到 1023。然而,在 pyFirmata 中,0 到 +5V 之间的值被线性转换为 0 和 1.0 的浮点值。例如,如果模拟引脚上的电压为 1V,Arduino 程序将测量一个大约为 204 的值,但当你使用 Python 中的 pyFirmata 的 read() 方法时,你会收到浮点值 0.2。

其他功能

除了已经描述的方法之外,pyFirmata库还提供了一些用于额外定制的实用函数,具体如下:

  • servo_config(pin,min_pulse=544,max_pulse=2400,angle=0):此方法有助于设置带有进一步定制的SERVO模式,例如最小脉冲值、最大脉冲值和起始角度。可以使用angle参数设置伺服电机的初始角度。
  • pass_time(seconds):此方法提供与默认 Python 的time模块提供的默认方法sleep()类似的功能。然而,pass_time函数提供了非阻塞的超时(以秒为单位)。

exit():我们建议你在完成代码运行后从pyFirmata断开 Arduino 板。这将释放串行端口,然后可以被其他程序使用:

board.exit()

get_firmata_version():此函数返回一个元组,包含 Arduino 板上 Firmata 协议的版本:

board.get_firmata_version()

即将提供的函数

pyFirmata库目前正在开发中,并持续接收更新以添加和改进各种方法。尽管大多数本地 Arduino 方法都通过 Firmata 协议在pyFirmata库中可用,但仍有一些函数尚未提供或正在开发中,具体如下:

  • pulseIn/pulseOut:这些是 Arduino 的本地函数,等待 Arduino 引脚达到指定的值。等待时间以微秒为单位返回。这种方法被 Ping(超声波距离测量)传感器广泛使用。使用pyFirmata实现此方法需要对标准的 Firmata 协议进行重大更改。
  • shiftIn/shiftOut:这些函数逐位将数据字节移入或移出。pyFirmata库缺少对这些函数的支持,可以使用各种 Python 编程技巧实现。

使用 Firmata 进行原型模板设计

本节的目标是提供原型模板,同时解释各种 Python 方法和编程技术。它试图涵盖一些最流行的传感器,并使用 DIY Arduino 项目中使用的编码示例。本节旨在利用 Firmata 协议实现这些 Python 程序。它还包括各种 Python 编程范式,如处理不定循环、创建自定义函数、处理随机数、从提示符获取手动输入等。这些原型模板设计得易于集成到大型项目中,或者可以作为围绕它们开发的大型项目的蓝图。在前一节中,你已经全面了解了pyFirmata包,我们将在接下来的示例中仅使用那些pyFirmata函数。本章后面将介绍支持 Firmata 协议的另一种 Python 库。

电位器 – 从模拟输入进行连续观察

电位器是一个可以通过旋钮控制的变阻器。它有三个端子,其中两个是 Vref 和地,而第三个提供可变输出。电位器的输出根据旋钮的位置在提供的电压之间变化。在 Arduino 中,您可以将电位器连接到+5V 和板子的地引脚,以提供供电电压。当可变端子与 Arduino 模拟输入接口时,这些电压值分别转换为 0 到 1023。在pyFirmata的情况下,模拟观察的值在 0 到 1 之间转换。

这个包含电位器的编码模板可以应用于需要外部手动控制系统项目的项目中。电位器的输出可以转换为 Arduino 的模拟输入,用于控制执行器,如电机或 LED。在某些情况下,输入也可以通过将其值应用于变量来控制程序的流程。

连接

将电位器的输出连接到如图所示的模拟引脚 A0。通过将电位器的 Vref 和地端子分别连接到+5V 和 Arduino 板的地来完成电路:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_04_01.jpg

Python 代码

假设您已经将StandardFirmata固件上传到 Arduino 板,您需要在计算机上运行 Python 代码来完成其与电位器的接口。本书代码包中提供了一个名为potentiometer.py的 Python 代码模板,可以帮助您开始这个示例,该模板可以从www.packtpub.com/books/content/support/1961下载。让我们打开这个文件来了解程序。如您所见,我们正在使用pyFirmata库以及其他 Python 模块,如timeos

from pyfirmata import Arduino, util from time import sleep import os 

在程序的第二步中,我们初始化 Arduino 板并开始在其上执行Iterator()函数:

port ='COM3' board = Arduino(port) sleep(5) it = util.Iterator(board) it.start()

一旦初始化了板子,我们需要为模拟引脚0分配一个角色,因为它将被用作输入引脚。我们使用get_pin()方法为模拟引脚0分配角色:

a0 = board.get_pin('a:0:i')

现在,作为主程序的一部分,我们需要持续监控我们刚刚定义的引脚a0上的电位器输出。我们使用while语句创建一个不定循环,用于脚本读取和打印模拟输入。这个不定while循环的问题在于,当程序被中断时,程序将无法正确关闭,并且它不会通过执行board.exit()方法来释放板子。为了避免这种情况,我们将使用 Python 编程范式中的另一个控制语句,称为try/except

try:whileTrue: p = a0.read()print p except KeyboardInterrupt: board.exit() os._exit()

使用此语句,程序将一直运行 while 循环,直到发生键盘中断,即 Ctrl + C,程序将执行 except 语句下的脚本。这包括使用 board.exit() 释放板子,以及使用 os._exit() 方法退出程序。总之,程序将持续打印电位器的输出,直到有人按下 Ctrl + C 来中断程序。

注意

Python 中的 try/except 语句提供了一种非常高效的方式来捕获异常。建议在整个开发过程中使用此语句来巧妙地调试你的程序。你可以从以下链接中了解 Python 错误和异常:

蜂鸣器 – 生成声音警报模式

数字蜂鸣器传感器被用于各种需要警报通知的应用。当它们接收到数字 HIGH 值(即 +5V)的供电时,这些传感器会发出声音,这可以通过使用 Arduino 的数字引脚来实现。类似于前一章中的 LED 示例,它们与 Arduino 的接口非常简单。然而,我们不是执行简单的数字输出,而是实现 Python 编程技巧来生成不同的声音模式和产生各种声音效果。相同的代码模板也可以用来生成不同的 LED 闪烁模式。

注意

www.amazon.com/Arduino-Compatible-Speaker-arduino-sensors/dp/B0090X0634 可以找到模拟数字蜂鸣器。

连接

如以下电路图所示,将传感器板的 VCC 和地连接到 5V 和 Arduino 板的地引脚。将传感器的信号引脚通过 220 欧姆电阻连接到数字引脚 2。你可以使用任何数字引脚来连接蜂鸣器。只需确保更新 Python 代码以反映你选择的引脚。

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_04_02.jpg

Python 代码

在代码示例中,使用时间延迟数组生成了两种不同的声音模式。为了执行这些操作,我们将实现一个自定义的 Python 函数,该函数将接受引脚号、重复时间和模式号作为输入。在我们跳到解释代码之前,让我们打开代码文件夹中的程序文件,buzzerPattern.py。在代码的开头,你可以找到将被主程序以适当选项调用的 Python 函数buzzerPattern()。由于这个函数是整个程序的核心,让我们尝试理解它。该函数包含两个硬编码的模式数组,pattern1pattern2。每个数组包含一个秒内蜂鸣器的开启和关闭时间,即模式的占空比。例如,在pattern1中,0.8代表蜂鸣器需要开启的时间,而0.2代表相反的情况。函数将重复指定的recurrence次该蜂鸣器模式。一旦启动了值为recurrencefor循环,函数将检查函数参数中的模式号并执行该模式。我们使用flag变量交替使用pattern数组中的元素来控制蜂鸣器。一旦整个重复循环完成,如果蜂鸣器是开启的,我们将完全关闭蜂鸣器,并使用exit()方法安全地断开板:

defbuzzerPattern(pin, recurrence, pattern): pattern1 =[0.8,0.2] pattern2 =[0.2,0.8] flag =Truefor i inrange(recurrence):if pattern ==1: p = pattern1 elif pattern ==2: p = pattern2 else:print"Please enter valid pattern. 1 or 2." exit for delay in p:if flag isTrue: board.digital[pin].write(1) flag =False sleep(delay)else: board.digital[pin].write(0) flag =True sleep(delay) board.digital[pin].write(0) board.exit()

小贴士

如果你想要更改时间延迟或实现完全不同的模式,你可以对pattern数组进行操作。

程序的其余部分相对简单,因为它包含导入库和初始化 Arduino 板的代码。一旦板被初始化,我们将使用输入参数(2, 10, 1)执行buzzerPattern()函数。这个参数将要求函数在引脚号 2 上播放pattern1 10 次:

from pyfirmata import Arduino from time import sleep port ='/dev/cu.usbmodemfa1331' board = Arduino(port) sleep(5) buzzerPattern(2,10,1)

直流电机 – 使用 PWM 控制电机速度

直流电机在机器人应用中得到了广泛的应用。它们的电压规格范围很广,取决于应用。在这个例子中,我们使用 5V 直流电机,因为我们想使用 Arduino 板本身供电。由于 Arduino 数字引脚只能有两种状态,即HIGH(+5V)或LOW(0V),仅使用OUTPUT模式无法控制电机的速度。作为解决方案,我们将通过支持 PWM 的数字引脚实现PWM模式。在使用pyFirmata时,配置为PWM模式的引脚可以接受 0 到 1.0 之间的任何浮点输入值,分别代表 0V 和 5V。

连接

根据负载,直流电机有时会消耗大量电流,并损害 Arduino 板。为了避免由于任何意外的大电流消耗而对 Arduino 板造成损害,我们将使用晶体管作为开关,它只使用少量电流来控制直流电机中的大量电流。为了完成以下图中显示的电路连接,您需要一个 NPN 晶体管(TIP120、N2222 或类似型号),一个二极管(1N4001 或类似型号)和一个 220 欧姆的电阻与您的直流电机连接。将晶体管的基极连接到也支持 PWM 模式的数字引脚 3。将剩余的组件按照图中的显示连接起来:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_04_03.jpg

注意

要了解更多关于晶体管端子(集电极、发射极和基极)的信息,以及将晶体管引脚与其相应的端子关联起来,您可以参考它们的规格书或以下网站:

Python 代码

用于直流电机的 Python 配方dcMotorPWM.py位于本书的代码包中,可以从www.packtpub.com/books/content/support/1961下载。打开 Python 文件,以进一步了解如何使用 PWM 控制直流电机的速度。自定义函数dcMotorControl()接受电机速度和时间持续时间作为输入参数,如以下代码片段所述:

defdcMotorControl(r, deltaT): pwmPin.write(r/100.00) sleep(deltaT) pwmPin.write(0)

就像之前的例子一样,我们使用类似的代码来导入必要的库并初始化 Arduino 板。初始化后,我们将数字引脚 3 的模式设置为PWM,这可以从get_pin('d:3:p')方法的利用中看出。这段代码反映了我们在上一节中学到的间接模式引脚模式分配方式:

# Set mode of pin 3 as PWM pwmPin = board.get_pin('d:3:p')

作为从用户收集手动输入的一部分,我们正在运行一个组合的try/except语句(在退出时释放板)和while语句(从用户获取连续输入)。代码模板引入了input()方法,从 Python 的交互式终端获取自定义值(电机速度和运行电机的持续时间)。一旦从用户那里获取了这些值,程序就会调用dcMotorControl()函数来执行电机动作:

try:whileTrue: r =input("Enter value to set motor speed: ")if(r >100)or(r <=0):print"Enter appropriate value." board.exit()break t =input("How long? (seconds)") dcMotorControl(r, t)except KeyboardInterrupt: board.exit() os._exit 

LED – 使用 PWM 控制 LED 亮度

在之前的模板中,我们使用 PWM 控制了直流电机的速度。也可以用同样的方法控制 LED 的亮度。在这个模板中,我们不会要求用户输入亮度,而是将使用 Python 模块 random。我们将使用此模块生成一个介于 1 和 100 之间的随机数,然后将其写入引脚,并随机改变 LED 的亮度。这个 randint() 函数是 random 模块提供的非常有用的功能,并且在通过快速发送随机信号测试原型时被广泛使用。

注意

randint() 函数采用 randint(startValue, endValue) 语法,并返回介于 startValueendValue 建立的范围内的随机整数。

连接

如同我们在上一章的项目中所用,我们需要一个上拉电阻将 LED 连接到 Arduino 引脚。如图所示,只需将 LED 的阳极(较长的一端)通过一个 220 欧姆的电阻连接到数字引脚 11,并将阴极(较短的一端)连接到地:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_04_04.jpg

需要注意的是,Arduino Uno 上的数字引脚 11 也能够与数字引脚 3、5、6、9 和 10 一起执行 PWM。

Python 代码

本练习的标题为 ledBrightnessPWM.py 的 Python 代码位于本书的代码包中,可以从 www.packtpub.com/books/content/support/1961 下载。打开文件以探索代码。正如您在这段代码模板中看到的,在将值传递到 PWM 引脚之前,会随机选择一个介于 0 和 1.0 之间的浮点数。这种方法可以在给定的时间内生成随机 LED 亮度。这种做法可以用于生成各种其他测试项目的随机输入样本。

如您所见,代码的前几行导入了必要的库并初始化了板。尽管板变量 /dev/cu.usbmodemfa1311 是为 Mac OS X 选择的,但您可以在以下代码片段中使用您操作系统的特定变量名。您可以从本章开头的 设置 Arduino 板 部分获取有关选择此变量名的更多信息。

from pyfirmata import Arduino, INPUT, PWM from time import sleep import random port ='/dev/cu.usbmodemfa1311' board = Arduino(port) sleep(5)

在这个例子中,我们正在使用直接方法分配引脚模式。正如您在以下代码片段中看到的,数字引脚 11 被分配到 PWM 模式:

pin =11 board.digital[pin].mode = PWM 

一旦分配了引脚模式,程序将使用 for 语句运行一个循环,同时随机生成一个介于 0 和 100 之间的整数,然后根据生成的数字向引脚发送适当的 PWM 值。执行此操作后,您将能够看到 LED 随机改变亮度,大约持续 10 秒:

for i inrange(0,99): r = random.randint(1,100) board.digital[pin].write(r /100.00) sleep(0.1)

在完成循环后,你需要关闭 LED 最后一次,然后安全地断开 Arduino 板。在退出板子之前关闭 LED 或任何连接的传感器是一个好习惯,以防止任何传感器意外运行:

board.digital[pin].write(0) board.exit()

注意

如果你想要均匀地使 LED 发光而不是随机改变其亮度,将for循环中的代码替换为以下代码片段。在这里,我们将 PWM 输入更改为递增变量i,而不是随机变量r

for i inrange(0,99): board.digital[pin].write(i /100.00) sleep(0.1)

伺服电机 – 将电机移动到特定角度

伺服电机是广泛应用于如云台相机控制、机械臂、移动机器人运动等需要精确电机轴运动的电子组件。这种对电机轴的精确控制是由于位置感应解码器,它是伺服电机组件的组成部分。标准伺服电机允许轴的角度在 0 到 180 度之间设置。pyFirmata库提供了可以在每个数字引脚上实现的SERVO模式。这个原型练习提供了一个模板和指南,用于将伺服电机与 Python 接口。

连接

通常,伺服电机有红色、黑色和黄色的线分别用于连接电源、地线和 Arduino 板的信号。将伺服电机的电源和地线连接到 5V 和 Arduino 板的地线。如图所示,将黄色信号线连接到数字引脚 13:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_04_05.jpg

如果你想要使用其他任何数字引脚,确保你在下一节的 Python 程序中更改引脚号。一旦你完成了适当的连接,让我们继续到 Python 程序。

Python 代码

包含此代码的 Python 文件命名为servoCustomAngle.py,位于本书的代码包中,可以从www.packtpub.com/books/content/support/19610下载。在 Python 编辑器中打开此文件。与其他示例一样,程序的起始部分包含导入库和设置 Arduino 板的代码:

from pyfirmata import Arduino, SERVO from time import sleep # Setting up the Arduino board port ='COM5' board = Arduino(port)# Need to give some time to pyFirmata and Arduino to synchronize sleep(5)

现在你已经准备好使用 Python 与 Arduino 板通信,让我们配置将要用来连接伺服电机的数字引脚。我们将通过将引脚 13 的mode设置为SERVO来完成此任务:

# Set mode of the pin 13 as SERVO pin =13 board.digital[pin].mode = SERVO 

setServoAngle(pin,angle)自定义函数接受伺服电机连接的引脚和自定义角度作为输入参数。这个函数可以用作涉及伺服电机的大型项目的组成部分:

# Custom angle to set Servo motor angledefsetServoAngle(pin, angle): board.digital[pin].write(angle) sleep(0.015)

在本模板的主要逻辑中,我们希望逐步将电机轴向一个方向移动,直到达到可达到的最大角度(180 度),然后以相同的增量速度将其移回原始位置。在while循环中,我们将要求用户输入以继续此程序,该输入将通过raw_input()函数捕获。用户可以输入字符y以继续此程序,或输入任何其他字符以终止循环:

# Testing the function by rotating motor in both directionwhileTrue:for i inrange(0,180): setServoAngle(pin, i)for i inrange(180,1,-1): setServoAngle(pin, i)# Continue or break the testing process i =raw_input("Enter 'y' to continue or Enter to quit): ")if i =='y':passelse: board.exit()break

在处理所有这些原型设计示例时,我们使用了通过使用数字和模拟引脚将传感器与 Arduino 连接的直接通信方法。现在,让我们熟悉另一种在 Arduino 和传感器之间广泛使用的通信方法,即 I2C 通信。

使用 I2C 协议进行原型设计

在上一节中,传感器或执行器通过数字、模拟或 PWM 引脚直接与 Arduino 通信。这些方法被大量基本、低级传感器使用,你将在未来的 Arduino 项目中广泛使用它们。除了这些方法之外,还有许多基于集成电路IC)的流行传感器,它们需要不同的通信方式。这些基于 IC 的高级传感器利用 I2C 或 SPI 总线方法与微控制器通信。由于我们将在即将到来的项目中使用基于 I2C 的传感器,本节将仅涵盖 I2C 协议和实际示例,以便更好地理解该协议。一旦你了解了 I2C 协议的基础,你就可以非常快速地学习 SPI 协议。

注意

你可以从以下链接了解更多关于 SPI 协议和 Arduino 支持的 SPI 库的信息:

1982 年,飞利浦公司需要找到一种简单高效的方法来在微控制器和电视上的外围芯片之间建立通信,这导致了 I2C 通信协议的开发。I2C 协议使用仅两条线将微控制器或 CPU 连接到大量低速外围设备。此类外围设备或传感器的例子包括 I/O 设备、A/D 转换器、D/A 转换器、EEPROM 以及许多类似设备。I2C 使用主从设备的概念,其中微控制器是主设备,外围设备是从设备。以下图示显示了 I2C 通信总线的示例:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_04_07.jpg

如前一个图所示,主设备包含两条双向线:串行数据线SDA)和串行时钟线SCL)。在 Arduino Uno 的情况下,模拟引脚 4 和 5 提供了 SDA 和 SCL 的接口。需要注意的是,这些引脚配置会随着 Arduino 板的不同版本而改变。作为从设备工作的外围传感器连接到这些线,这些线也由上拉电阻支持。主设备负责在 SCL 上生成时钟信号,并与从设备初始化通信。从设备接收时钟并响应主设备发送的命令。

从设备顺序并不重要,因为主设备通过从设备的部分地址与其通信。为了初始化通信,主设备会在总线上发送以下类型之一的消息,并带有特定的部分地址:

  • 在从设备上写入数据的单个消息
  • 读取从设备数据的单个消息
  • 读取从设备数据的多个消息

要在 Arduino 编程中支持 I2C 协议,Arduino IDE 配备了一个名为 Wire 的默认库。您可以通过在程序开头添加以下代码行将此库导入到您的 Arduino 绘图中:

#include <Wire.h>

为了初始化 I2C 通信,Wire 库使用以下函数的组合在从设备上写入数据:

Wire.beginTransmission(0x48); Wire.write(0); Wire.endTransmission();

这些从设备使用独特的部分地址进行区分。正如前一个示例中所示,0x48 是连接的从设备的部分地址。

Wire 库还提供了 Wire.read()Wire.requestFrom() 函数来读取和请求从设备的数据。这些函数将在下一节中详细解释。

注意

您可以从以下链接中了解更多关于 I2C 协议和 Wire 库的信息:

Arduino I2C 接口示例

为了练习 I2C 协议的原型设计练习,让我们利用两个流行的 I2C 传感器,这些传感器可以检测环境中的温度和光照。作为理解 I2C 消息的第一步,我们将使用 Arduino 绘图进行 I2C 接口操作,稍后,我们将使用 Python 开发类似的功能。

为 TMP102 温度传感器编写的 Arduino 代码

TMP102 是广泛使用的数字传感器之一,用于测量环境温度。与传统的模拟温度传感器(如 LM35 或 TMP36)相比,TMP102 提供了更好的分辨率和精度。以下是 TMP102 的图片:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_04_08.jpg

上一张图片展示了一个带有 TMP102 传感器可用引脚的扩展板。请注意,您获得的 TMP102 传感器可能具有与图片中显示的不同的引脚布局。在连接任何电路之前,始终建议检查您的传感器扩展板的数据表。如图所示,TMP102 传感器支持 I2C 协议,并配备了 SDA 和 SCL 引脚。将 Arduino Uno 板的模拟引脚 4 和 5 连接到 TMP102 传感器的 SDA 和 SCL 引脚。此外,按照以下图示连接 +5V 和地线。在这个例子中,我们使用 Arduino Uno 板作为主设备,TMP102 作为从设备外设,其中 TMP102 的部分地址为十六进制的 0x48

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_04_09.jpg

注意

您可以从 SparkFun Electronics 购买 TMP102 传感器扩展板,链接为www.sparkfun.com/products/11931

您可以从www.sparkfun.com/datasheets/Sensors/Temperature/tmp102.pdf获取该板的数据表。

现在,使用 USB 线将您的 Arduino 板连接到计算机,并在 Arduino IDE 中创建一个新的草图,使用以下代码片段。一旦在 Arduino IDE 中选择了适当的串行端口和板类型,上传并运行代码。如果所有步骤都按描述执行,则在执行时,您将在 串行监视器 窗口中看到温度读数,以 摄氏度华氏度 显示:

#include <Wire.h>int partAddress =0x48; void setup(){ Serial.begin(9600); Wire.begin();} void loop(){ Wire.requestFrom(partAddress,2); byte MSB = Wire.read(); byte LSB = Wire.read();int TemperatureData =((MSB <<8)| LSB)>>4;float celsius = TemperatureData*0.0625; Serial.print("Celsius: "); Serial.println(celsius);float fahrenheit =(1.8* celsius)+32; Serial.print("Fahrenheit: "); Serial.println(fahrenheit); delay(500);}

在前面的代码片段中,Wire.requestFrom(partAddress,2) 函数从从设备 TMP102 请求两个字节。从设备发送数据字节到主设备,这些字节被 Wire.read() 函数捕获,并存储为两个不同的位:最高有效位MSB)和最低有效位LSB)。这些字节被转换为整数值,然后通过乘以从数据表中获得的 TMP102 传感器的增量分数,将其转换为实际的摄氏读数。TMP102 是最容易与 Arduino 接口的 I2C 传感器之一,因为可以通过简单的 I2C 请求方法获取传感器值。

Arduino 编码用于 BH1750 光传感器

BH1750 是一种数字光传感器,用于测量特定区域内的可见光量。尽管各种 DIY 项目使用简单的光敏电阻作为便宜的替代品,但 BH1750 传感器因其高分辨率和精度而广泛应用于各种应用。环境光,也称为光通量或流明,以流明为单位测量。BH1750 传感器支持使用部分地址 0x23 的 I2C 通信,如果您使用多个 BH1750 传感器,则次要地址为 0x5C。以下是一个典型的 BH1750 扩展板的图片:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_04_10.jpg

将 BH1750 扩展板的 SDA 和 SCL 引脚连接到 Arduino Uno 板的模拟引脚 4 和 5,如以下电路图所示。同时,完成+5V 和地线的连接,如以下图所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/py-prog-ardn/img/5938OS_04_11.jpg

在前面的例子中,我们使用了Wire库中的函数来完成 I2C 通信。尽管BH1750是一个简单且方便的 I2C 传感器,但在具有多种测量能力的传感器情况下,直接使用Wire库进行编码并不方便。在这种情况下,您可以使用由制造商或开源社区开发的特定于传感器的 Arduino 库。对于BH1750,我们将演示如何使用此类库来辅助 I2C 编码。在我们能够使用此库之前,我们必须将其导入到 Arduino IDE 中。了解将库导入到 Arduino IDE 的过程非常重要,因为您将在未来重复此过程来安装其他库。执行以下步骤将BH1750库导入到您的 Arduino IDE 中:

  1. 下载并解压第七章,中期项目 – 一个便携式 DIY 恒温器,代码示例在一个文件夹中。
  2. 打开 Arduino IDE 并导航到草图 | 导入库… | 添加库…
  3. 当被要求选择目录时,请前往下载文件中的BH1750文件夹,然后点击选择
  4. 要检查您的库是否已安装,导航到草图 | 导入库…,并在下拉列表中查找BH1750

最后,重启 Arduino IDE。

提示

如果您使用的是版本 1.0.4 或更早版本的 Arduino IDE,您可能无法在菜单中找到**导入库…**选项。在这种情况下,您需要遵循arduino.cc/en/Guide/Libraries上的教程。

BH1750库有一个直接获取环境光值的方法。让我们使用内置的代码示例来测试这个库。

在重启 Arduino IDE 后,导航到文件 | 示例 | BH1750,打开BH1750test Arduino 草图。这应该在 Arduino IDE 中打开以下代码片段。设置合适的串行端口并将代码上传到您的 Arduino 板。一旦代码执行,您将能够使用 Arduino IDE 的串行监视器检查光通量(lux)值。请确保串行监视器配置为 9600 波特率:

#include <Wire.h>#include <BH1750.h> BH1750 lightMeter; void setup(){ Serial.begin(9600); lightMeter.begin(); Serial.println("Running...");} void loop(){ uint16_t lux = lightMeter.readLightLevel(); Serial.print("Light: "); Serial.print(lux); Serial.println(" lx"); delay(1000);}

如您从前面的代码片段中看到的,我们通过包含 Wire.h 文件中的 BH1750.h 文件来导入 BH1750 库。这个库提供了 readLightLevel() 函数,它将从传感器获取环境光值并提供为整数。由于 Arduino 代码以 1000 毫秒的延迟在循环中运行,lux 值将每秒从传感器获取并发送到串行端口。您可以在 串行监视器 窗口中观察到这些值。

PyMata 用于快速 I2C 原型设计

我们一直使用 pyFirmata 作为我们的默认 Python 库来接口 Firmata 协议。pyFirmata 库是一个非常有用的 Python 库,用于开始使用 Firmata 协议,因为它提供了许多简单而有效的方法来定义 Firmata 端口及其角色。由于这些原因,我们在前面的部分中广泛使用了 pyFirmata 进行快速原型设计。尽管 pyFirmata 支持模拟、数字、PWM 和 SERVO 模式,并提供了易于使用的方法,但它对 I2C 协议的支持有限。

在本节中,我们将使用一个名为 PyMata 的不同 Python Firmata 库来熟悉基于 Python 的 I2C 传感器的原型设计。PyMata 库支持常规的 Firmata 方法,并提供对 I2C 消息协议的全面支持。

PyMata 可以通过 Setuptools 轻松安装,我们在前面的章节中使用它来安装其他 Python 库。我们假设您已经在计算机上安装了 Setuptools 和 pip。让我们开始执行以下步骤:

  1. 如果前述命令的执行失败,您需要检查安装过程是否有任何错误。解决错误并重复安装过程。

如果一切设置正确,此过程将无错误完成。您可以通过在 Python 的交互式提示符中打开并导入 PyMata 来确认 PyMata

>>>import PyMata 

如果您正在使用 Linux 或 Mac OS X,请在终端中使用以下命令安装 PyMata 库:

$ sudo pip install pymata 

要在 Windows 计算机上安装 PyMata,请在命令提示符中执行以下命令:

C:\> easy_install.exe pymata 

使用 PyMata 接口 TMP102

为了利用 PyMata 的功能,您需要确保您的 Arduino 板安装了标准的 firmata 固件,就像 pyFirmata 库一样。在我们继续解释 PyMata 的功能之前,让我们首先运行以下代码片段。按照上一节中的说明连接 TMP102 温度传感器。使用 Arduino IDE,导航到 文件 | 示例 | Firmata,并将标准 Firmata 脚本上传到您的 Arduino 板。现在,使用以下代码片段创建一个 Python 可执行文件。如果需要,将端口的值(COM5)更改为操作系统所需的适当端口名称。最后,运行程序:

import time from PyMata.pymata import PyMata #Initialize Arduino using port name port = PyMata("COM5")#Configure I2C pin port.i2c_config(0, port.ANALOG,4,5)# One shot read asking peripheral to send 2 bytes port.i2c_read(0x48,0,2, port.I2C_READ)# Wait for peripheral to send the data time.sleep(3)# Read from the peripheral data = port.i2c_get_read_data(0x48)# Obtain temperature from received data TemperatureSum =(data[1]<<8| data[2])>>4 celsius = TemperatureSum *0.0625print celsius fahrenheit =(1.8* celsius)+32print fahrenheit firmata.close()

在执行前面的代码片段时,你将能够在华氏和摄氏温度下看到温度读数。正如你从代码中的内联注释中可以看到,使用 PyMata 初始化端口的第一步是使用 PyMata 构造函数。PyMata 通过 i2c_config() 函数支持配置 I2C 引脚。PyMata 还通过 i2c_read()i2c_write() 函数支持同时读写操作。

使用 PyMata 接口 BH1750

对于 BH1750 来说,前面的 PyMata 代码片段经过少量修改后可以用来获取环境光传感器数据。作为第一个更改,你想要将 TMP102 的部分地址(0x48)替换为 BH1750 的地址(0x23)在下面的代码片段中。你还需要将传感器接收到的原始值转换为 lux 值,使用给定的公式。完成这些修改后,从终端运行以下程序:

import time from PyMata.pymata import PyMata port = PyMata("COM5") port.i2c_config(0, port.ANALOG,4,5)# Request BH1750 to send 2 bytes port.i2c_read(0x23,0,2, port.I2C_READ)# Wait for BH1750 to send the data time.sleep(3)# Read data from BH1750 data = port.i2c_get_read_data(0x23)# Obtain lux values from received data LuxSum =(data[1]<<8| data[2])>>4 lux = LuxSum/1.2printstr(lux)+' lux' firmata.close()

在运行前面的代码片段后,你将能够在终端看到环境光传感器的 lux 读数。这个过程可以用于大量 I2C 设备来读取注册信息。在复杂的 I2C 设备中,你必须遵循它们的规格书或示例来组织 I2C 的读写命令。

有用的 pySerial 命令

标准的 Firmata 协议和 Python 的 Firmata 库对于测试或快速原型化 I2C 传感器非常有用。尽管它们有很多优点,但基于 Firmata 的项目面临以下缺点:

  • 实时执行中的延迟:基于 Firmata 的方法需要一系列的串行通信消息来接收和发送数据,这增加了额外的延迟并降低了执行速度。
  • 不必要的空间:Firmata 协议包含大量额外的代码来支持各种其他 Arduino 功能。在一个定义良好的项目中,你实际上并不需要完整的函数集。
  • 有限支持:尽管 Firmata 的某个版本包括 I2C 支持,但如果不添加延迟,实现复杂的 I2C 函数相当困难。

总结来说,你总是可以使用基于 Firmata 的方法来快速原型化你的项目,但在你从事生产级或高级项目时,你可以使用替代方法。在这些情况下,你可以使用由 Python 的串行库 pySerial 支持的定制 Arduino 代码,以启用非常特定的功能通信。在本节中,我们将介绍一些有用的 pySerial 方法,如果你必须直接使用库的话。

连接到串行端口

一旦你将 Arduino 连接到电脑的 USB 端口,你就可以使用 Serial 类在 Python 代码中打开端口,如下面的代码示例所示:

import serial port = serial.Serial('COM5',9600, timeout=1)

除了端口号和波特率之外,你还可以使用Serial()指定一系列串行端口参数,如timeoutbytesizeparitystopbits等。在执行pySerial库中的任何其他命令之前,必须初始化串行端口。

从端口读取一行

一旦串行端口打开,你可以开始使用readline()读取端口。在初始化端口时,readline()函数需要指定超时,否则代码可能会因异常而终止:

line = port.readline()

readline()函数将处理端口中每个以换行符\n终止的行。

清除端口以避免缓冲区溢出

在使用pySerial时,有必要清除输入缓冲区以避免缓冲区溢出并保持实时操作:

port.flushInput()

如果端口的波特率较高且输入数据处理较慢,可能会发生缓冲区溢出,降低执行速度并使体验变得缓慢。

关闭端口

完成过程后关闭串行端口是一种良好的编码实践。这种做法可以在 Python 代码终止后消除端口阻塞问题:

port.close()

摘要

在本章中,你学习了成功将 Arduino 板与 Python 接口所需的重要方法。你还被介绍了各种具有实际应用的原型代码模板。这些原型模板帮助我们学习新的 Python 编程范式和 Firmata 方法。在章节的后面部分,我们进一步深入原型设计,通过学习更多关于传感器与 Arduino 板之间建立通信的不同方式。尽管我们通过这些原型示例涵盖了大量的编程概念,但本章的目标是让你熟悉接口问题,并为你的项目提供快速解决方案。

我们假设你现在已经熟悉使用 Python 和 Arduino 测试你的传感器或项目原型。现在是时候开始着手创建具有复杂 Python 功能(如用户控制、图表和绘图)的应用程序了。在下一章中,我们将为你的 Python-Arduino 项目开发自定义图形用户界面(GUI)。

Read more

【大数据存储与管理】分布式文件系统HDFS:07 HDFS编程实践

【大数据存储与管理】分布式文件系统HDFS:07 HDFS编程实践

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈大数据技术原理与应用 ⌋ ⌋ ⌋专栏系统介绍大数据的相关知识,分为大数据基础篇、大数据存储与管理篇、大数据处理与分析篇、大数据应用篇。内容包含大数据概述、大数据处理架构Hadoop、分布式文件系统HDFS、分布式数据库HBase、NoSQL数据库、云数据库、MapReduce、Hadoop再探讨、数据仓库Hive、Spark、流计算、Flink、图计算、数据可视化,以及大数据在互联网领域、生物医学领域的应用和大数据的其他应用。 【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/BigData_principle_application。 文章目录 * 一、HDFS常用命令 * 二、HDFS的Web页面 * 三、HDFS常用Java API及应用实例 * (一)常用Java API介绍 * (二)应用实例 * 总结

By Ne0inhk
【优选算法】滑动窗口算法:专题一

【优选算法】滑动窗口算法:专题一

目录 引言:  【209. 长度最小的子数组】 题目描述: 实现核心及思路: 思路可视化: 代码实现: 【无重复字符的最长子串】 题目描述: 实现核心及思路: 思路可视化: 代码实现: 【最大连续1的个数III】 题目描述: 实现核心及思路: 代码实现: 【1658.将x减到0的最小操作数】 题目描述: 实现核心即思路: 代码实现: 引言: 滑动窗口?用两个指针维护一个动态的 “窗口” 区间,通过移动指针来扩大或缩小窗口,在一次遍历中完成计算,时间复杂度通常为 O (n)。 典型应用:寻找最长无重复字符的子串找到和为目标值的最短子数组字符串的排列匹配 一般步骤(模板): (1)定义left 和 right 指针同时指向数组首元素; (2)当符合要求时,right++,模拟进窗口; (3)不满足要求时,left++,模拟出窗口; (4)

By Ne0inhk

淘特App x-sign签名逆向实战:从抓包到算法还原

1. 从抓包开始:定位淘特App的核心签名参数 大家好,我是老张,在移动安全这块摸爬滚打十来年了。最近有不少朋友在聊淘特App,说它的风控机制相比主站要“友好”一些,是个不错的逆向分析练手对象。今天,我就带大家走一遍完整的实战流程,从最基础的抓包开始,一步步定位到那个关键的 x-sign 签名参数,最后尝试还原它的生成算法。整个过程我会尽量讲得细一些,哪怕你是刚入门的新手,跟着做下来也能有收获。 咱们先搞定抓包。工欲善其事,必先利其器,我习惯用 Charles,当然你用 Fiddler 或者 HttpCanary 都行,原理相通。关键一步是给测试手机安装好 Charles 的根证书,并完成代理设置,确保能截获 HTTPS 流量。一切就绪后,打开淘特App,随便进行一个操作,比如搜索一个商品或者查看商品详情。这时,Charles 的界面里应该会刷出一大堆请求。 别被这么多请求吓到,我们的目标很明确:找到那些携带了签名参数的请求。通常,

By Ne0inhk
【算法通关指南:算法基础篇】二分算法:1.在排序树组中查找元素的第一个和最后一个位置 2.牛可乐和魔法封印

【算法通关指南:算法基础篇】二分算法:1.在排序树组中查找元素的第一个和最后一个位置 2.牛可乐和魔法封印

🔥小龙报:个人主页 🎬作者简介:C++研发,嵌入式,机器人方向学习者 ❄️个人专栏:《算法通关指南》 ✨ 永远相信美好的事情即将发生 文章目录 * 前言 * 一、二分算法 * 二、在排序树组中查找元素的第一个和最后一个位置 * 2.1题目 * 2.2 算法原理 * 2.3代码 * 三、牛可乐和魔法封印 * 3.1题目 * 3.2 算法原理 * 3.3代码 * 总结与每日励志 前言 本专栏聚焦算法题实战,系统讲解算法模块:以《c++编程》,《数据结构和算法》《基础算法》《算法实战》 等几个板块以题带点,讲解思路与代码实现,帮助大家快速提升代码能力ps:本章节题目分两部分,比较基础笔者只附上代码供大家参考,其他的笔者会附上自己的思考和讲解,希望和大家一起努力见证自己的算法成长 一、

By Ne0inhk