树莓派机器人学习指南-全-
树莓派机器人学习指南(全)
原文:
zh.annas-archive.org/md5/1b93b9c4b1bfe059dc37139b9a8c8e47译者:飞龙
前言
欢迎来到《使用 Raspberry Pi 学习机器人技术》!在本书中,你和我将共同踏上一段激动人心的冒险,穿越电子学、编程和机器人技术的世界。我将向你展示如何利用 Raspberry Pi 迷你计算机从零开始构建你自己的可定制机器人。
在这个过程中,我们将进行一系列项目,赋予你的机器人强大的功能,从遥控、沿线路行走,到识别物体,甚至更多!
本书结束时,你将掌握编程和工程技能,为未来几年从事机器人和计算机科学的乐趣奠定基础,并且拥有实现你最疯狂机器人创意所需的基本知识。
本书还介绍了许多计算机领域的其他知识,包括用最流行的编程语言之一——Python 进行编程。这是任何对计算机和技术感兴趣的人的完美第一步!
为什么要构建和学习机器人?
机器人无处不在。它们制造你每天使用的产品。它们在手术中拯救生命。它们甚至探索火星和我们太阳系的其他地方。随着科技的进步,人类越来越依赖机器人来让我们的生活更轻松、更美好、更安全。随着人工智能的兴起,像无人驾驶汽车和智能机器人伴侣这样的事物不久后将成为常态!
现在是学习机器人技术的最佳时机,无论是为了满足自己的好奇心,还是为了开启未来有利可图的职业生涯。而且,如果你了解一点机器人知识,你将更有机会在机器人起义时生存下来。(开个玩笑。)
通过构建机器人,你将获得各个领域的经验和理解。做东西?检查! 电子工程?检查! 软件编程?检查! 本书是这三者的完美入门。
除了这些,我可以将为什么你应该构建机器人总结为一句话:因为它很有趣。看到自己做的东西在地板上跑来跑去,避开障碍物,或者闪烁灯光,总有一种独特的吸引力和兴奋感,你亲手创造的东西能这样运作,真是太酷了。
机器人让我在 13 岁时进入了计算机科学的世界,从此便再也没有放开过。
为什么选择 Raspberry Pi?
Raspberry Pi 是一款 35 美元的信用卡大小的计算机,旨在为人们提供一个廉价的编程和电子学入门。尽管体积小且价格低廉,每一块 Pi 都是一台功能完整的计算机,能够做几乎所有你所期待的事情,从运行程序到文字处理、网页浏览等。
Raspberry Pi 是学习机器人技术的一个极佳平台。它便宜、体积小、容易供电,并且非常易于获取。你几乎可以用任何编程语言编程 Pi,并将其嵌入各种电子项目中。Pi 在性能和简便性之间达到了一个恰到好处的平衡,这意味着你可以毫无限制地创建机器人。
自 2012 年从英国剑桥推出以来,树莓派获得了全球范围内的广泛关注和社区支持。数以百万计的人在线分享他们的进展、项目和想法,这让初学者很容易向更有经验的人学习和提升。全球也有许多线下活动,你可以在这些活动中与人交流、展示自己的成果,这些活动通常被亲切地称为树莓果派聚会,并在全球各地举行。
本书内容是什么?
本书以项目为基础,围绕一款两轮机器人展开,我将向你展示如何从零开始制作它。你将通过一个个项目改进这个机器人,添加新部件并编写新功能的代码。在书中的每个阶段,我都会提供全面的构建说明和程序解析。你也可以免费下载完整的代码和资源,访问 nostarch.com/raspirobots/。书中的任何更新或附加说明也可以在那里找到。
看看每一章为你准备了什么内容:
第一章:开始使用 带你了解树莓派及其功能。我还会教你如何安装操作系统,并通过 SSH 在本地网络中设置和使用它。在这一章中,你将初次接触终端,并编写你的第一个 Python 程序。
第二章:电子学基础 介绍电流、电力是什么以及我们如何利用它。在这一章中,你将找到两个适合初学者的项目,非常适合在开始做机器人之前进行练习。到最后,你将能够制作能闪烁 LED 并响应按钮的电路。
第三章:构建你的机器人 开启你的机器人之旅。在这里你将开始构建你的机器人!我们将建立机器人底座,安装电机和轮子,并提供关于机器人各个部分及其连接方式的详细指导。
第四章:让你的机器人移动 让你完全构建的机器人具备移动的能力,使用任天堂 Wiimote 进行完整的远程控制。你将使用 Python 代码让机器人移动,首先是简单的模式,然后只需倾斜和调整 Wiimote,就像马里奥赛车一样。
第五章:避开障碍物 给你带来了机器人自主性的初步体验。在这个项目中,你将使用超声波距离传感器,使你的机器人能够感知并避开前进道路上的障碍物。从此,你再也不会发生碰撞了!
第六章:用灯光和声音进行定制 让你为机器人定制超亮的灯光和扬声器。你将能够编程制作自己炫目的灯光秀,并将 3.5 毫米扬声器连接到树莓派,让机器人发出像汽车喇叭一样的声音。
第七章:循迹 教你如何使用传感器和代码让你的机器人沿着黑线行驶。它很快就能自己在赛道上竞速!
第八章:计算机视觉:跟踪彩色球 是本书中最先进的项目,它介绍了图像处理,这是计算机科学中最前沿的领域之一。在这一章中,你的机器人将使用官方的树莓派摄像头模块和计算机视觉算法来识别和跟踪彩色球,无论它在机器人环境中的哪个位置。
这本书适合谁阅读?
通过树莓派学习机器人技术是一本适合任何对机器人、编程和电子学感兴趣的人的书。书中没有假设读者的能力,并且我在全书中避免使用任何令人困惑或没有解释的术语。所有年龄和背景的人都可以从易于跟随的项目和指导中学到东西。
你应该在哪里购买零件?
在本书及其中的项目中,你将需要各种各样的零件:电子元件、制作材料以及一些其他工具。不过不用担心——所有的材料都是实惠且广泛可用的。每一章都会有具体的建议,但一般来说,所有你需要的材料都可以在 eBay、亚马逊等网站上找到。
本书中的所有电子元件都可以从像 eBay(https://www.ebay.com**/)这样的在线商店购买,或是像 Adafruit(https://www.adafruit.com**/)、Pimoroni(https://shop.pimoroni.com**/)、The Pi Hut(https://thepihut.com/)、CPC Farnell(http://cpc.farnell.com**/)和 RS Components(http://uk.rs-online.com/web**/)等专门的电子商店购买。这个列表并不完全,你可能在自己的国家找到更便宜、更近的在线零售商。你甚至可能幸运地有一个本地的电子硬件商店,你可以在那里购买所需的材料!
我将在每个项目中介绍并解释你需要的具体部件,但以下是你在本书中将使用的所有部件的完整列表:
第一章
-
树莓派 3 型号 B+
-
8GB+ microSD 卡
-
HDMI 线,USB 键盘/鼠标
-
5V 微型 USB 电源适配器
第二章
-
400 点面包板
-
一个 LED 和适当的电阻
-
M-F/F-F/M-M 跳线
-
瞬时按钮
第三章
-
适合你机器人的底盘(我用乐高做的)
-
两个带轮胎的 5V 至 9V 有刷电机
-
六节 AA 电池盒
-
六节 AA 电池(我推荐可充电的)
-
LM2596 降压转换器模块
-
L293D 电机驱动芯片
第四章
-
任天堂 Wii 遥控器
-
针对早期型号: 蓝牙适配器(适用于 3/Zero W 型号之前的树莓派)
第五章
-
HC-SR04 超声波距离传感器
-
一个 1 kΩ电阻和一个 2 kΩ电阻
第六章
-
带接头的 NeoPixel 条形灯
-
一个小型 3.5 毫米扬声器
第七章
- 两个基于 TCRT5000 的红外线循迹传感器模块
第八章
-
官方树莓派摄像头模块
-
一个彩色球
你在过程中也会用到这些工具/材料:
-
各种螺丝刀
-
热熔胶枪
-
万用表
-
焊接铁
-
剥线钳
-
软粘剂/魔术贴/3M 双锁扣
让我们开始吧!
简而言之:机器人和树莓派太棒了。现在这一切都说清楚了,我们也算认识了,接下来就是开始动手的时候了!只需翻到下一页,开启你的机器人冒险之旅……
第一章:启动和运行
本书将教你如何构建你自己的机器人。这次激动人心的冒险将涉及各种电子学、制作和编程。
在接下来的章节中,我将带你完成所有需要了解的内容,从连接 LED、按钮、电池和电机,到让你的机器人跟踪线路、为其安装传感器以观察世界等等!你将在所有接下来的项目中使用 Raspberry Pi,所以现在你已经知道它是什么了,接下来我们开始配置你的 Pi 吧。
获取一块 Raspberry Pi
在你开始之前,当然需要一块 Raspberry Pi!Raspberry Pi 在全球范围内都有售,所以无论你住在哪里,都应该很容易买到一块。
在本文撰写时,有几种不同型号的 Raspberry Pi 可供选择。最新的两款是 Raspberry Pi 3 Model B+ 和 Raspberry Pi Zero。前者是经典的更新版 35 美元 Raspberry Pi,如 图 1-1 所示。这是我在本书中将使用的板子,因为它是开发的最佳选择:它具有更多的全尺寸连接器。这样你就不必为 Pi Zero 需要的转接器和 USB 集线器而烦恼。

图 1-1 Raspberry Pi 3 Model B+
Raspberry Pi Zero 是一块简化版、较小的板子,售价仅为 5 美元。Pi Zero W 与之相同,只不过是 无线 版,意味着它配备了 Wi-Fi 和蓝牙功能,售价为 10 美元。Zero 和 Zero W 如 图 1-2 所示。
你可能会想,为什么我们不使用更小巧的 Pi Zero。毕竟,更小的板子占用空间更少,这样你就可以做更小的机器人,或者有更多空间放置硬件。但是,如果你使用 Pi Zero,你将需要 USB 和 HDMI 转接器来连接 USB 设备或显示器,这会更具挑战性。而且这些转接器还需要单独购买。当你在机器人领域积累了更多经验后,或许会决定在以后的项目中使用 Pi Zero;到时候,就去试试吧!

图 1-2 左边是 Raspberry Pi Zero,右边是 Raspberry Pi Zero W
如果你已经拥有旧型号的 Pi,不必担心。你拥有的 Raspberry Pi 版本其实并不重要,因为所有版本都能互相兼容,你可以使用任何一款来构建本书中的机器人。唯一的区别是,你需要为像无线互联网连接这样的设备准备适配器。表 1-1 提供了每种型号的不同规格。
表 1-1 主要 Raspberry Pi 型号规格对比
| 型号 | Raspberry Pi 3 Model B+ | Raspberry Pi Zero | Raspberry Pi Zero W |
|---|---|---|---|
| 内存 | 1GB | 512MB | 512MB |
| 处理器 | 64 位四核 1.4GHz | 32 位单核 1GHz | 32 位单核 1GHz |
| 端口 | HDMI, 4x USB 2.0, Micro-USB 电源 | Mini-HDMI, Micro-USB(数据), Micro-USB 电源 | Mini-HDMI, Micro-USB(数据), Micro-USB 电源 |
| 连接性 | Wi-Fi, 蓝牙, 以太网 | 无 | Wi-Fi, 蓝牙 |
| 价格 | $35 | $5 | $10 |
如果你还没有树莓派,我推荐购买树莓派 3 Model B+。树莓派有时会推出新版本,但在确保向后兼容(意味着它们能与早期版本兼容)方面会格外小心,因此即使发布了更高版本,你依然可以跟随本书的内容进行操作。
注意
树莓派不是你能用来制作机器人的唯一平台或计算机,但它是最简单且最易接触到的方式之一!
你可以在树莓派基金会网站上找到你所在国家的经销商 (www.raspberrypi.org/products)。
你对树莓派的第一次接触
当你第一次看到你的树莓派时,你可能会感到迷惑。你可能会将普通的“计算机”与屏幕、键盘、鼠标和存储器联系在一起——但树莓派有些不同。
拆开包装,你会看到一块外观看起来简陋的电路板,板上有各种组件。如果你拥有的是树莓派 3 B+,它应该与图 1-3 完全相同。后续版本可能看起来稍有不同,但它们都有相同的基本特性。

图 1-3 树莓派 3 Model B+ 的顶部视图
让我们来看看这些组件的作用:
USB 端口 这里有四个 USB 端口,你可以用它们插入 USB 键盘、鼠标、U 盘和其他设备。
以太网网络端口 这是用于有线互联网连接的端口。
HDMI 端口 HDMI 代表 高清多媒体接口,这个端口是你将树莓派连接到电视或计算机显示器等屏幕时使用的接口。
Micro USB 电源接口 这是你插入每个树莓派所需的 5V 电源的地方;这个接口与许多手机的电源输入相同。还值得注意的是,它没有电源按钮!只要你保持电源线连接,树莓派就会一直开机。
MicroSD 卡槽 大多数计算机都有某种形式的内置存储——例如,你的笔记本通常有硬盘——而树莓派没有“板载”存储。相反,你的计算机运行的软件(也就是 操作系统,简称 OS)以及所有文件都存储在 microSD 卡中,就像你在数码相机中找到的那种存储卡一样。在设置过程中,我将向你展示如何配置 microSD 卡,并安装树莓派所需的操作系统。
四核 1.4GHz 处理器 在你的 Pi 中,你会看到计算机的大脑。你可能会好奇你新购买的设备有多强大:它是否像笔记本电脑或台式机一样快?该处理器配合 Pi 的 1GB 内存,赋予了 Raspberry Pi 大致相当于某些智能手机的计算能力。正如你稍后将发现的那样,借助这个处理器,你可以进行大量的计算。
摄像头连接器 在 HDMI 端口旁边是一个夹状的连接器,标有camera(摄像头)。这是官方 Raspberry Pi 摄像头模块的输入端——你将在本书中使用它来赋予你的机器人“看”世界的能力!
GPIO 引脚 Raspberry Pi 最独特的特点之一是板子顶部边缘的 40 个闪亮的金属引脚,如图 1-4 所示。这些被称为GPIO 引脚,代表通用输入/输出引脚。你可以编程控制这些引脚,以操作各种电子设备、元件和其他部件,包括 LED、传感器和电机(参见图 1-5)。

图 1-4 GPIO 引脚

图 1-5 可以通过 GPIO 引脚连接到 Raspberry Pi 的硬件选择
注意
原版 Raspberry Pi 1 只有 26 个 GPIO 引脚。它们的功能完全相同,但在后来的 Raspberry Pi 型号中,基金会成功地在板上增加了 14 个引脚!如果你使用的是原版模型,你仍然可以按照本书中的说明进行操作,因为较新的 40 引脚 Raspberry Pi 的前 26 个引脚与原版完全相同,并且向后兼容。
这些 GPIO 引脚是进入物理计算世界的门户。你将使用它们来连接你机器人中的电子元件(电机、循迹传感器等)。接下来,我将引导你通过编程这些新硬件,使它们按你的指令工作!
所需物品
正如你已经注意到的,你的新计算机缺少一些基本功能,比如屏幕和键盘。你将需要一些额外的硬件来将其设置并启动。幸运的是,你可能已经拥有大部分这些硬件。
5V Micro-USB 电源适配器 用于为 Raspberry Pi 提供电力。任何旧的 Android 智能手机充电器都可以。大多数电源适配器都会列出它们的输出电压和电流,因此你只需要确保充电器的输出电压为 5V,并且输出电流至少为 2.5A。很多电源适配器不符合这个规格。使用这些电源适配器时,常常会遇到一些神秘的故障。如果你没有备用电源适配器,可以在这里购买一个官方的:https://www.raspberrypi.org/products/raspberry-pi-universal-power-supply/。
USB 键盘和鼠标 默认情况下,树莓派没有输入设备,所以你需要一只 USB 键盘和鼠标来与树莓派进行初步交互。如果你家里有台台式电脑,直接拔掉现有的 USB 键盘和鼠标就可以用了。如果没有,你可以在网上或者任何电脑商店购买。
8GB 以上的 microSD 卡 如前所述,树莓派没有内置存储,所以你需要一张 microSD 卡(如果你使用的是第一代树莓派,还可以用普通 SD 卡)来存储操作系统。这些卡也可以在网上或者电脑商店购买。你至少需要一张 8GB 的卡,空间越大越好!
HDMI 线缆 这将用于将你的树莓派连接到 HDMI 电视或显示器。这是一种标准线缆,你可以在网上或本地商店购买。
显示器或电视 你需要一些显示输出设备来连接你的树莓派。任何带有 HDMI 端口的设备都可以使用,无论是电脑显示器、电视,还是其他类型的屏幕。许多电脑显示器有 DVI 输入端口,你可以购买一个 HDMI 转 DVI 适配器或者直接使用 HDMI 转 DVI 的线缆。
如果你能使用台式电脑或笔记本电脑,那将非常有帮助。虽然这不是必需的,但在很多方面都会有优势。首先,你需要准备一张 SD 卡来安装树莓派的操作系统,而这需要在另一台机器上完成。其次,你将通过局域网无线连接树莓派并进行控制。这样你就不需要反复插拔树莓派与显示器连接,而且你还需要一台独立的电脑。通过局域网控制树莓派,你只需要在本章的初始设置过程中使用显示器或电视。这不应该超过半小时!
如果你无法访问另一台电脑,不用担心。你依然可以绕过这个问题,顺利完成后续步骤。
在本书的后续章节中,我们将使用更多的硬件、组件和电子设备,但你现在不用担心这些。我会在每个项目开始前告诉你所有需要了解的内容。
设置树莓派
现在你已经准备好了所有的硬件,是时候设置你的树莓派了。对于初学者来说,这看起来可能是一项艰巨的任务,但我会一步步带你完成。你只需要设置好 microSD 卡,连接硬件,然后启动树莓派并配置几个设置即可。
如果你无法使用其他电脑来跟随接下来的步骤,你可以购买已经预装操作系统的 microSD 卡。这些可以通过搜索“预装 NOOBS 树莓派 microSD 卡”在线找到。
如果你有另一台电脑可用,建议你自己安装操作系统,因为这是一项非常实用的技能。这样,如果出现问题需要重新安装操作系统,你也知道该怎么做。而且,预装的 microSD 卡也比较贵!
在 Windows/macOS 上安装树莓派操作系统
操作系统是每台现代计算机上运行的软件,尽管不同的操作系统可能看起来非常相似,但它们并不完全相同。你可能最熟悉 Windows 或 macOS,但你的 Raspberry Pi 运行的是 Linux 操作系统。
Linux 是一系列免费的开源操作系统,拥有不同的发行版,意味着针对不同的目的有不同版本的 Linux。对于 Raspberry Pi,大多数人使用 Raspbian 发行版,这是 Raspberry Pi 基金会官方支持的操作系统(见图 1-6)。Raspbian 经开发和优化,能够在你的 Pi 上流畅运行,你会发现它与你常用的操作系统有许多共同点。
开源是什么意思?
当我们说软件是开源的,我们指的是源代码——构建软件所需的代码——是公开的,任何人都可以查看、修改和分发。这意味着全球的程序员可以为开源项目做出贡献,致力于最终用户的共同利益。这也意味着 Raspbian 可以免费下载和使用。一些操作系统,如 Windows,是专有的,需要购买许可证密钥才能在电脑上使用。

图 1-6 Raspbian 桌面环境
警告
在格式化过程中,你所选择的存储设备将被完全且不可逆地清除。确保你再次确认选择了正确的驱动器名称,以免不小心删除了其他设备上的所有内容并丢失数据。
准备你的 SD 卡
在你能在 microSD 卡上安装 Raspbian 之前,你需要先清除卡上可能已经存储的任何内容。即使你的卡是全新的,我也建议你这样做,因为有时它可能已经包含一些内容。这个过程叫做格式化你的 microSD 卡。在格式化之前,请务必阅读边栏中的警告!
-
将你的 microSD 卡插入到普通电脑中。一些电脑有 SD 卡或 microSD 卡插槽,但许多电脑没有。如果你的电脑没有可以插入 SD 卡的插口,你需要使用USB SD 卡适配器,就像图 1-7 中展示的那样。这个小设备让你可以将卡插入到电脑的 USB 插槽中。你可以在网上轻松便宜地找到它(只需搜索“SD 卡 USB 适配器”)或在当地的电脑商店购买。
-
一旦你将 SD 卡插入,你应该能够在文件资源管理器中找到它。如果你使用 Windows,查看“设备和驱动器”;如果你使用 Mac,使用 Finder 查找它。记下你的 microSD 卡的驱动器名称。这是你的电脑在插入时为其分配的字母(例如 D: 或 H:)。
-
确保你的 SD 卡完全擦除并正确格式化的最佳方式是使用官方格式化软件SD 卡格式化工具。要安装这个软件,请访问https://www.sdcard.org/downloads/,点击菜单中的SD 内存卡格式化工具,并找到适合你操作系统的格式化工具。它会要求你接受条款,滚动到页面底部并点击接受以继续,最新版本的软件将开始下载。下载完成后,运行安装程序,如图 1-8 所示。确保按照指示操作并接受条款和条件。
-
安装过程完成后,找到并运行 SD 卡格式化程序。一个像图 1-9 中所示的窗口将会打开。接下来的过程非常简单:从下拉菜单中选择你的卡(记住之前记下的驱动器名称),保持选择快速格式化选项,然后点击格式化。观察进度条,直到卡片成功格式化!

图 1-7 我的 USB 适配器已连接到我的笔记本电脑,准备进行格式化

图 1-8 SD 卡格式化程序的安装过程

图 1-9 SD 卡格式化程序正在运行并格式化我的 8GB microSD 卡(驱动器D:)
安装 NOOBS
现在你有了一张空白且已经格式化的 microSD 卡,是时候将 Raspbian 操作系统安装到卡上了。借助NOOBS(来自树莓派基金会的全新开箱软件),这个过程变得异常简单。只需要按照以下步骤操作:
-
将 microSD 卡插入计算机,访问树莓派官方网站https://www.raspberrypi.org/。点击页面顶部的下载,然后点击NOOBS链接。确保下载最新的完整版NOOBS——不要安装 Lite 版本,因为它无法让你设置树莓派,除非连接到互联网。找到标有下载 ZIP的按钮并点击。等待操作系统下载。根据互联网速度,这可能需要几分钟到几个小时不等。
-
下载完成后,找到位于你的下载文件夹中的 NOOBS,并解压压缩文件。在 Windows 系统中,右键点击文件,选择全部解压,选择一个位置保存解压后的操作系统文件,然后点击解压。在 Mac 系统中,通过 Safari 下载的 NOOBS 文件会自动为你解压。
-
最后,找到你新下载的 NOOBS 文件,将它们复制并粘贴到你的 microSD 卡中。你可以通过鼠标选中所有文件,复制它们,然后粘贴到已经格式化的卡上,如图 1-10 所示。

图 1-10 将所有提取的文件转移到 microSD 卡
太棒了!你已经成功设置了 SD 卡,并可以安全地将其从计算机中取出。在移除之前,确保右键点击设备并弹出卡片。
插入电源和连接线缆到你的树莓派
下一阶段是物理上设置你的树莓派。你需要在一个有足够空间、可以连接 Wi-Fi 网络并且能够接入显示器(无论是电视还是计算机屏幕)的地方进行操作。
-
拆开你的树莓派并将 microSD 卡插入主板底部的卡槽(参见图 1-3 以回忆插槽的位置)。确保卡插到底。一些型号的树莓派(如 1 B+和 2 B)在卡插入正确时会发出“咔哒”声,但后来的 3 B/B+型号则不会。
-
将 USB 键盘和鼠标连接到树莓派的 USB 端口。
-
将 HDMI 线缆插入树莓派的 HDMI 端口。将另一端插入电视或显示器。
-
现在,要启动树莓派,将 5V Micro-USB 电源线连接到 HDMI 端口旁的电源输入端口(参见图 1-11)。你应该会看到 LED 灯闪烁,并且屏幕上会有一些活动。恭喜!你已经让树莓派“复活”!
如果屏幕上什么都没有显示,试着用遥控器切换不同的 HDMI 输入源来找到正确的输入——大多数屏幕都有多个输入源。作为一个常规的操作建议,你应该在插入树莓派电源之前先打开显示器;如果顺序颠倒,某些显示器可能无法接收到 HDMI 信号!所以,试着先关掉显示器,插入 HDMI 线,再打开显示器,然后将 5V 微型 USB 电源线插入树莓派。

图 1-11 一台正常工作的树莓派
如果你想使用有线互联网连接,并且离路由器很近,你可以通过将以太网线从路由器插入树莓派旁边的以太网端口来连接互联网。然而,整本书中我会使用无线互联网连接,我建议你也这样做,以便自由活动。
如果你在屏幕右上角看到一个闪电符号,这表示树莓派警告你电源供应不足,系统可能会不稳定。在这种情况下,你应该使用更好的电源供应器,理想情况下是官方的电源。
安装 Raspbian
在连接到树莓派的屏幕上,你应该看到一个 NOOBS 界面,类似于图 1-12 中显示的界面。现在,你只需要安装并配置 Raspbian 操作系统。这非常简单,你很快就能开始使用!
要安装操作系统,只需点击 Raspbian 选项旁边的框,然后点击 NOOBS 框顶部的安装。Raspbian 应该会自动提取并为你设置 SD 卡。坐下来放松,观看进度吧!

图 1-12 NOOBS 安装界面
一旦安装过程完成,你的 Pi 应该会重新启动并进入 Raspbian 桌面环境,如之前在 图 1-6 中所示。
其他 Pi 操作系统
如果你将 NOOBS 界面连接到互联网,你将能够下载并访问许多其他的 Raspberry Pi 操作系统。你可以安装许多不同版本的 Linux,每个版本都有其优缺点。例如,OSMC(开源媒体中心)是一个视频播放发行版,用于将 Raspberry Pi 连接到电视作为媒体中心。我们将在本书中始终使用官方的 Raspbian 操作系统。如果你想尝试其他系统,可以通过重启 Raspberry Pi 并按住 SHIFT 键返回 NOOBS 设置界面。
你会发现,一个“欢迎使用 Raspberry Pi”的设置向导会自动启动。由于我们稍后会手动更详细地配置 Raspberry Pi 的偏好设置,可以通过点击 Cancel 选项关闭该向导。
你会注意到,Raspbian 环境与你可能使用过的其他操作系统非常相似。你会看到屏幕顶部有菜单栏,如 图 1-13 所示,应用程序位于左侧,实用工具(例如音量和 Wi-Fi)位于右侧。花点时间探索一下吧!

图 1-13 Raspberry Pi 菜单
配置 Raspbian
在继续之前,有两件事你应该立即做,以配置 Raspbian,从而节省以后的时间:更改一些偏好设置和设置 Wi-Fi。
更改 Raspbian 偏好设置
当 Raspbian 安装时,默认情况下会关闭一些重要功能。这是出于安全性和效率的考虑,并且因为很多人并不需要这些功能。然而,你 将 需要其中一些功能,所以我们现在就启用它们,这样你以后就不用再去设置了。
在屏幕的左上角,点击 Pi 图标,然后从菜单中选择 Preferences ▸ Raspberry Pi Configuration。你应该会看到一个像 图 1-14 中的对话框。

图 1-14 Raspberry Pi 配置对话框,打开的是系统标签
当应用程序首次打开时,你会看到系统标签。在这里,你可以更改账户密码、屏幕分辨率和其他设置。
默认情况下,你的 Raspberry Pi 会自动登录。标准用户配置文件的用户名是 pi,密码是 raspberry。我建议你将密码更改为自己选择的内容,以提高 Raspberry Pi 的安全性。请记住这个密码,因为将来你需要它来登录。
在你能够设置 Wi-Fi 之前,你需要告诉 Raspberry Pi 你所在的国家。为此,请点击 Localization 标签,然后点击 Set WiFi Country。从下拉菜单中选择你当前所在的国家。
修改完密码后,导航到下一个标签页,接口(Interfaces)。在这里,将以下选项从禁用(Disabled)更改为启用(Enabled):
-
相机
-
SSH
-
VNC
-
SPI
-
I²C
启用相机将允许你连接官方的 Raspberry Pi 相机模块,我们将在本书的最后一章进行连接。启用 SSH 和 VNC 将允许你通过本地网络远程访问你的 Pi,稍后我会向你展示如何操作。其他两个选项——SPI 和 I²C——都与 GPIO 引脚上的功能相关,我们将在后面的章节中遇到这些。
启用这些设置后,点击确定,然后在提示时重启你的 Raspberry Pi。
将你的 Raspberry Pi 连接到互联网
将 Raspberry Pi 连接到 Wi-Fi 网络应该只需要几分钟。如前所述,你可以通过物理以太网线将 Pi 连接到互联网——这不需要任何配置。然而,当你在构建机器人时,你希望一切尽可能无线,所以我建议使用 Wi-Fi。
还需要注意的是,为了下载我们在本书中将使用的软件和代码,你的 Pi 需要连接到互联网。
Raspberry Pi 3 B+和 Pi Zero W 都内建了 Wi-Fi 和蓝牙。如果你使用的是旧型号,你需要购买一个 USB Wi-Fi 适配器,并将其插入 Pi 的 USB 端口来连接互联网。某些 Wi-Fi 适配器可能与 Pi 连接时出现问题,因此我推荐使用官方型号,你可以在https://www.raspberrypi.org/products/raspberry-pi-usb-wifi-dongle/购买。
若要从桌面连接到 Wi-Fi 网络,只需点击屏幕右上角的 Wi-Fi 图标,屏幕下拉列表中将显示本地网络,如图 1-15 所示。选择你的网络,输入密码,然后点击确定。

图 1-15 Wi-Fi 下拉菜单
菜单栏图标应会改变,显示你的 Wi-Fi 信号强度,表示你的 Pi 现在已经连接到互联网。
终端的奇妙世界
终端(或称为shell)是你直接给电脑指令的一种方式。具体来说,它是一个你可以输入并执行基于文本的命令的界面。这与现代操作系统使用的图形用户界面(简称GUI,发音为“gooey”)相对,后者通常被称为桌面。GUI 允许你通过简单而直观的方式使用计算机完成许多高级任务。如果你以前没有使用过 Raspberry Pi 或 Linux 机器,你很可能只用过计算机的 GUI。
在计算机没有足够的处理能力使用复杂图形之前,用户完全通过终端和命令行界面操作计算机。这是一种纯粹基于文本的与计算机交互方式:你输入文本命令告诉计算机做什么,计算机则通过输出文本来回应。
这可能听起来像是一种过时且不太有用的与计算机交互的方式,但它依然非常强大。使用终端可以让你通过仅仅几个字符高效地执行精确的命令。树莓派终端是我们与机器人互动的主要方式。
终端巡游
随着你在本书中的学习,你会变得更加熟悉并且自信地使用终端。现在,为了帮助你熟悉终端,我将带你快速了解它,并介绍它是如何工作的。
要从桌面打开终端窗口,点击左上角的树莓派菜单,然后点击附件 ▸ 终端。一个黑色的框应该会出现,如图 1-16 所示。现在,你正在使用终端!

图 1-16 树莓派终端
终端会显示一个类似这样的提示符:
pi@raspberrypi:~ $
注意
在你的树莓派和 Linux 冒险中,如果你不确定某个命令的功能,或者想知道如何在终端中执行某个操作,最好的学习方法是在线查找相关信息。有大量的帮助和命令行手册可以指导你完成这个过程——无论你想用终端做什么!
在这种情况下,提示符只是你的树莓派等待你输入文本命令;它在提示你做某事。不幸的是,终端无法理解普通英语(或其他任何语言)。相反,你需要使用特定的命令与它进行交流。这些是预定义的短语和字符序列,告诉终端如何执行。虽然有成千上万的命令,但不用担心。我现在会介绍一些简单的命令给你。
你可以像在普通操作系统中一样,通过终端访问不同文件夹(称为目录)中的文件。不同之处在于,终端界面就像一个基于文本的文件管理器。在任何时候,你都“处于”某个目录中,并且可以随时更改位置。为了探索这一点,让我们练习一些命令。
当你打开终端时,你会进入树莓派的主目录。你可以使用第一个命令ls来查看当前目录中的文件和文件夹。换句话说,ls 列出了当前目录的内容。使用你的键盘,在终端中输入这个命令:
pi@raspberrypi:~ $ ls
按下 ENTER 键。你应该会看到当前目录中存储的目录和文件列表,如图 1-17 所示。现在,通过进入附件 ▸ 文件管理器,在桌面上打开同一个文件夹,应该与终端中看到的内容一致。

图 1-17 树莓派终端与图形文件管理器并排显示,以不同的方式展示相同的内容
你会注意到文本用不同的颜色编码。这有助于你快速识别项目。蓝色的项目是目录。那段明亮的绿色文本是你的用户名——在这个例子中是默认用户,pi。
你像在文件管理器中那样,使用命令cd(表示更改目录)在这些文件夹之间导航。选择刚刚由ls列出的一个目录,然后输入以下命令:
pi@raspberrypi:~ $ cd that_directory
将that_directory替换为你的目录名。例如,我将通过以下命令进入Documents目录:
pi@raspberrypi:~ $ cd Documents
这会将我移入Documents文件夹。需要注意的是,终端是区分大小写的,这意味着终端会将大写字母和小写字母视为不同的字符;例如,d与D并不相同。如果我没有将Documents中的D大写,而是输入了documents,我的 Pi 就无法理解我要去哪里,并会返回错误。
当你移动文件夹时,你应该会注意到在$提示符前的蓝色文本也会发生变化,像这样:
pi@raspberrypi:~/Documents $
终端会通过在提示符前列出当前位置来告诉你当前在文件系统中的位置。这将非常有用。
在你的新文件夹中,再次输入***ls***,查看其中包含的文件和文件夹。当我在Documents文件夹中这样做时,得到的输出是列表 1-1。
pi@raspberrypi:~/Documents $ ls
BlueJ Projects Greenfoot Projects Scratch Projects
列表 1-1 从终端查看我的Documents文件夹
如你所见,列出了新目录的不同内容。命令cd ..将带你回到你刚才所在的文件夹。你可以把它当作是将你“向上”移动到上一级目录路径。所以,在Documents文件夹中运行cd ..,会将你带回到主目录。
注意
输入长目录名既麻烦又容易出错。命令经常出现错误、拼写错误或返回错误信息。所以,这里有两个快速提示!首先,当你使用cd命令或任何其他文件命令时,在输入目录或文件名的前几个字母后,按下 TAB 键。这将自动完成目录名称。现在试试看。第二,如果命令出错,或者你想再次执行或编辑它,可以使用上下箭头键滚动浏览你的命令历史。
你应该知道的最后一个(也是非常重要的)命令是shutdown。树莓派没有电源开关,你需要拔掉电源线来断开它的电源。在每次拔掉电源之前,你需要安全地关闭操作系统。每当你想关闭树莓派时,运行此命令:
pi@raspberrypi:~ $ sudo shutdown now
之后,稍等片刻,然后你可以放心地拔掉电源线。
通过这一点,我向你介绍了两个最有用的 Linux 终端命令:ls和cd。在你的树莓派冒险中,你将经常使用它们。我们在本书的过程中还会使用许多其他终端命令,我将在接下来的部分逐一向你介绍。
从另一台计算机访问你的树莓派
设置树莓派很简单,但一直连接到显示器可能会带来不便。当你的机器人在地板上快速移动时,你不想让长电缆拖在后面,所以现在我将向你展示如何从另一台计算机访问你的树莓派,这样你就可以无线发送指令给你的机器人。
你可以使用SSH(一种代表安全外壳的互联网协议)从同一网络上的另一台计算机远程访问树莓派的终端。然后,你可以向该计算机的命令行输入命令并查看其响应,就像你在前一部分所做的那样,并将它们发送到你的机器人。
首先,你的树莓派必须连接到本地网络,可以通过 Wi-Fi 或以太网连接,另一个设备也必须连接到同一网络。
接下来,你需要你的树莓派的IP 地址以便稍后连接到它。它是一个互联网协议地址,是分配给每个连接到网络的设备的唯一数字标签。可以把它当作计算机的“住址”来理解。
要查找树莓派的 IP 地址,只需打开终端并输入以下命令:
pi@raspberrypi:~ $ ifconfig
这将生成大量的输出文本。它可能看起来很混乱,但你的 IP 地址就在其中。
如果你是通过 Wi-Fi 连接到网络的,请向下滚动到wlan0条目,在inet后的数字就是你的 IP 地址;参见图 1-18 我的 IP 地址。如果你是通过以太网连接的,你可以在eth0条目下找到你的 IP 地址。无论如何,只需在输出中找到以inet 192.168.1.221(或类似的内容)形式出现的魔法序列。

图 1-18 ifconfig命令的输出。我已高亮显示了我的 IP 地址——如果你是通过 Wi-Fi 连接的,你应该在这里找到你的 IP 地址。
如你所见,我的 IP 地址是 192.168.1.221。记下你的 IP 地址(它可能非常相似),因为你将使用此信息从其他设备连接到你的树莓派。
接下来,你需要在另一台计算机上设置 SSH 连接。SSH 内置于 Linux 发行版和 macOS 中,但在 Windows 上,你需要一些第三方软件。我将接下来讲解如何从 Windows 和 Mac 连接到你的 Pi;你只需要阅读与自己计算机相关的部分。
在 Windows 上使用 SSH
Windows 所需的免费软件叫做 PuTTY。安装过程非常简单,只需几分钟:
-
在你的 Windows PC 上,打开一个网页浏览器并导航到 http://www.putty.org/,然后按照链接访问下载页面。根据你的计算机选择 32 位或 64 位选项。这将下载安装程序。
-
打开安装程序并按照说明安装 PuTTY 软件。
-
安装程序完成后,打开 PuTTY 应用程序。你可以在开始菜单中找到 PuTTY 的快捷方式。每次打开应用程序时,你将看到类似于 图 1-19 中的窗口。
![image]()
图 1-19 PuTTY 应用程序和配置对话框
-
要连接到你的 Raspberry Pi,请在标记为“Host Name(或 IP 地址)”的框中输入你的 Pi 的 IP 地址。下面确保选中 SSH,除非你知道其他设置,否则将端口选项保持为 22。点击打开以开始连接。
-
如果这是你第一次连接到新的 Pi,可能会看到安全警告;只需点击是并同意。之后,会出现密码提示。输入你 Pi 的密码并按 ENTER;如果你之前没有更改过,默认密码是 raspberry。
现在,你可以使用完整的 Raspberry Pi 终端,如 图 1-20 所示。为什么不尝试一下在上一节中学到的一些命令呢?

图 1-20 PuTTY Shell
在 macOS 上使用 SSH
在任何 Mac 计算机上使用 SSH 都不需要额外的软件。你可以直接使用 Mac 自带的终端程序!
-
在你的 Mac 上的任何地方,按住 COMMAND 键和空格键打开 Spotlight 搜索。输入
**terminal**并按 ENTER。一个命令行窗口应会打开。 -
要连接到你的 Raspberry Pi,请在终端中输入以下命令,将
***your_ip_address***替换为你之前找到的实际 IP 地址:$ ssh pi@your_ip_address
如你在 图 1-21 中看到的,我输入的命令是:
$ ssh pi@192.168.1.221
-
如果这是你第一次连接到新的 Pi,可能会看到安全警告;只需输入
***yes***来同意。然后,你将需要输入 Raspberry Pi 的密码并按 ENTER;如果你之前没有更改密码,那么默认密码是 raspberry。

图 1-21 Mac 终端 SSH 连接过程
现在你应该可以使用完整的 Raspberry Pi 终端了!尝试一下在上一部分中学到的一些命令!
什么是编程?
你已经差不多准备好开始构建机器人了!在本章的最后,我想向你介绍一些编程概念。
编程是编写一组指令的过程,指示计算机如何执行任务。你可以编写视频游戏、应用程序,甚至在我们的案例中,机器人。你能用计算机和编程做的唯一限制就是你的想象力!
在本书的过程中,我将向你展示如何连接电子元件,然后编程让它们做你想要的事情。如果你之前从未进行过编程,不用担心。我会在整个书中逐步解释所有内容。如果你遇到困难,你还可以从https://nostarch.com/raspirobots/下载你需要的所有代码。
介绍 Python
有许多不同的编程语言,每种都有其优缺点。本书中我们将使用的语言叫做Python。Python 是一种高级编程语言,这意味着它比许多其他编程语言更接近人类语言,因此既易于理解又非常强大。
你将编写 Python 程序,并从终端执行它们。这意味着你可以使用 SSH 从另一台计算机编程你的 Raspberry Pi,而无需将其连接到显示器。
编写你的第一个 Python 程序
对于你的第一个程序,按照极客传统,创建一个计算机程序,使其输出,或显示,“你好,世界!”给用户。这是一个简单的任务,能帮助你熟悉如何编写和运行 Python 程序。
-
从终端中输入以下命令:
pi@raspberrypi:~ $ mkdir robot
-
此命令将为你创建一个名为robot的新目录,用来存储你自己的 Python 程序。从现在起,我们会将所有程序存储在这个目录中。使用以下命令进入你的新目录:
pi@raspberrypi:~ $ cd robot
-
接下来,在你新建的robot目录中,输入以下命令:
pi@raspberrypi:~/robot $ nano hello_world.py
-
Nano 是一个文本编辑器。文本编辑器是允许你创建、查看和更改文本文件的简单软件。Nano 让你可以直接在终端中创建和编辑程序,而不需要打开任何其他窗口。此命令使用 Nano 创建一个名为hello_world.py的新文件——文件扩展名.py告诉 Nano 这是一个 Python 程序。通过此命令,一个空的hello_world.py文件已被创建并保存在我们的robot目录中。这个文件现在已经在你的终端中打开。
-
当 Nano 在你的终端中打开时,你可以输入指令保存到hello_world.py文件中。输入以下这一行 Python 代码:
print("你好,世界!")
-
命令
print()是一个 Python 函数。在编程中,函数 是执行任务的指令。print()只会将你提供给它的文本输出到终端!在我们的例子中,我们提供的文本是"Hello, world!``"。在编程中,任何两个引号之间的一系列字符都被称为 字符串。 -
你的单行程序现在已经完成,接下来需要退出并保存你的工作。在 Nano 中,按 CTRL-X。然后会提示你是否要保存所做的更改。按 Y 表示确认保存。接下来 Nano 会问你要将这些指令保存为哪个文件名,在我们的案例中是 hello_world.py。按 ENTER 确认。你现在应该回到命令行了。
-
你已经创建了程序,现在需要运行它。从终端运行 Python 程序,只需输入
***python3***后跟文件名即可。输入以下命令来执行你的程序:pi@raspberrypi:~/robot $ python3 hello_world.py
你将在终端窗口看到字符串 " Hello, world!``",如 图 1-22 所示。

图 1-22 你的第一个 Python 程序的输出
你可能注意到命令 python3 helloworld.py 中的 3。这表示告诉你的 Pi 使用 Python 3 来执行文件,而不是 Python 2。Python 3 是 Python 的最新版本,虽然 Python 2 仍然被广泛使用,但推荐使用 Python 3。它们之间的差异不大,但在语法和功能上有一些不同。本书中的所有项目都将使用 Python 3。
总结
在这一章中我们已经涵盖了很多内容!你已经了解了你的新 Raspberry Pi,完成了设置,并且初步体验了终端和 Python 编程。现在你可以远程访问和使用你的 Pi,并且理解如何进行一些操作,比如更改偏好设置和设置 SD 卡。
在下一章中,我将介绍电子学和电力的基础知识,并且你将开始做一些简单的建设工作,例如闪烁 LED 等小项目。这将为你打下基础知识,帮助你在进入机器人制作之前做好准备!
第二章:电子学基础
电子学是控制和操作电能以完成有用工作的科学。它是关于使电子元件,如灯光、传感器和马达,做出你想要它们做的事情。
许多创新都源自电子学的不同领域。对我们来说,最有趣的是机器人学这一分支。要制作自己的机器人,你需要了解电子学的基础知识,并将这些知识运用自如!在这一章中,我将通过两个项目让你初步接触电子学。你将编程控制一个 LED(发光二极管)按一定间隔闪烁,然后连接一个按钮,使其在按下时向终端打印信息。你很快就能让 LED 闪烁并控制物理世界了!
什么是电力?
电力无处不在,贯穿我们日常生活的方方面面:电流被用来为电器和家电提供动力,比如家中的灯光、电视屏幕、烤面包机,以及树莓派机器人的马达。那么,电力到底是什么呢?
电力从原子开始。世界上万物都是由数十亿个微小的原子组成的——包括你!正如你在科学课上学到的,原子本身由三种粒子组成:质子、中子和电子。质子和中子一起位于原子的中心,形成原子的原子核,而电子则围绕这个原子核运动,正如在图 2-1 中所示。

图 2-1 一个原子的示意图
质子和电子各自带有电荷,这是物质的基本属性。质子带正电,电子带负电。中子没有电荷;也就是说,它们是中性的。你可能听过“异性相吸”这句话,这在这里也适用。因为质子和电子的电荷相反,它们互相吸引并保持在一起,形成了构成你周围一切的原子。
原子有许多不同的排列方式,叫做元素。每种元素由原子中所含的质子、电子和中子数量来定义。例如,铜元素通常有 29 个质子和 35 个中子,而金元素则有 79 个质子和 118 个中子。所有金属,如铜、金和铁,都是由原子集合压在一起组成的。某些材料是导电的,这意味着当给予能量时,一个原子的电子可以移动到下一个原子。这会导致物质中产生电荷流动,也就是我们所说的电流。通过材料中某一点的电子流量的大小称为电流,单位为安培(A)。
要使电流流动,必须有一个完整的电路。电路是一个封闭的路径,就像一个环路,电流在其中流动。电路必须由导电材料构成,电流才能通过,如果电路中有任何间隙,电流就无法流动。
电路需要一个能“推动”电流流动的能量来源。这个来源可以是电池、太阳能电池板、电网或其他任何东西。关键是,这些来源提供了势差,也就是电压。电压简单地推动电子通过导体(如铜线),而电压的强度是以伏特(V)为单位的。
电源有正极和负极。在简单的电路中,就像图 2-2 所示,电池的正负极可以通过一根粗铜线连接。电子带负电,因此被电池的正极吸引,它们沿着电路从负端流向正端,电压推动着它们流动。

图 2-2 显示电荷流经连接电池正负极的粗铜线的电路。
尽管电子是从负极到正极流动的,但通常我们习惯认为电流是从正极到负极流动的。电路中的电池有一个固定的电压。如果这个电压增加,更多的电子会被推动穿过电路,电流也会变大。相反,如果电压减少,推动穿过电路的电子会更少,电流也会变小。
电阻
现在你已经理解了电路的基本概念,我们需要加入另一个元素:电阻。电阻简单来说就是减少电流的流动。除了实验室外,所有材料都有一定的电阻,电阻的单位是欧姆(Ω)。我们可以通过想象一根水管来理解电阻。流经水管的水就像流经铜线的电流。假设水管的一端比另一端高,水管高端的水比低端的水有更多的能量(势能)。如果水管是水平的,水就不会流动;如果水管略微倾斜,就会有小的水流。实际流量取决于水管两端的高度差和水管的宽度。水管的高度差就像电压(势差)。
另一方面,电阻就像是压缩水管,影响水管的宽度:越是压缩,能流过的水就越少(参见图 2-3)。这就意味着电流通过电路的量会减少。

图 2-3 电阻减少了电流通过电路的量。
因此,电路由三个要素组成:电压、电流和电阻。它们似乎都紧密相连,对吧?你甚至可能认为它们之间一定有某种数学关系或定律,你是对的。
欧姆定律
欧姆定律处理的是电压、电流和电阻之间的关系。它指出,导体两端的电压与通过它的电流成正比。
让我们分解一下,看看这意味着什么。在电路中,电压等于电流乘以电阻。我们用V表示电压,用I表示电流,用R表示电阻。所以,电压的方程式写作如下:

和任何数学方程式一样,你可以重新排列方程式来求解其他项的方程式。例如,根据欧姆定律,我们知道电路中的电流等于电压除以电阻。当你重新排列电流和电阻的方程时,你会得到以下方程:

R = 
如果这些内容有些让你感到困惑,不用担心!当你制作自己的电路时,这些内容会变得更容易理解。现在我们已经讲解了一些电力和电子学的基础知识,接下来就让我们开始制作吧!
制作 LED 闪烁:树莓派 GPIO 输出
就像“Hello, world!”是传统的第一个程序一样,制作 LED 闪烁也是传统的第一个电子项目,因为它非常巧妙地展示了如何使用 GPIO 引脚作为输出。这个项目将是你使用树莓派 GPIO 引脚的入门介绍。在我们开始之前,你可能会有一些问题。
首先,什么是 LED?LED 是发光二极管(light-emitting diode)的缩写,LED 是当电流通过时会发光的元件。LED 是现代版的老式灯泡,但它们耗电更少、不发热且使用寿命更长。
部件清单
在你初次涉足电子学时,除了你之前设置的树莓派外,还需要一些额外的东西。以下是这个项目所需的材料:
注意
关于如何购买和获取这些部件的指导,请参阅介绍部分。
-
一个面包板
-
一个 LED(你选择的颜色)
-
一个合适的电阻
-
跳线
在我们接线这些组件之前,我会再稍微解释一下它们是如何工作的,以及你为什么需要它们。
面包板
电子 面包板 允许你连接电子元件,而无需将它们永久连接在一起(这叫做 焊接;参见第 204 页的《如何焊接》)。这意味着你可以通过将元件插入面包板的孔来快速原型电路。面包板孔之间的间距是标准化的(2.54 mm/0.1 英寸),因此所有适合面包板的元件都应该能轻松安装。面包板有几种不同大小,孔的数量也不同(也称为 接点)。我推荐使用一个 400 接点的面包板,像图 2-4 中展示的那样。

图 2-4 一个 400 接点的面包板及其行列连接示意图
在图 2-4 中,你可以看到面包板的行和列是如何通过金属条相互连接的。因此,如果你将一个元件放入一行,并将另一个元件放入同一行,例如,它们将在电路中相互连接。
LED
LED 有各种不同的形状、大小和颜色。幸运的是,它们也非常便宜。当大宗购买时,它们每个的价格简直就是 几分钱。确保你的 LED 有两个脚,可以安排以适应你的面包板,如图 2-5 所示。

图 2-5 一款蓝色 LED
随便购买任何你喜欢颜色的 LED——我选择了蓝色。确保检查你购买的 LED 的电压规格。你需要确保点亮 LED 所需的电压小于 3.3 V。这通常被称为 正向电压。你通常可以在 LED 的在线清单中找到这些信息。我的 LED 的正向电压是 2.5 V。树莓派的 GPIO 引脚工作在 3.3 V,如果你的 LED 正向电压是 5 V,例如,你的树莓派将无法点亮它!
你还需要查明 LED 的正向电流。正向电流是推荐通过元件的电流。我这款 LED 的推荐正向电流是 30 mA(毫安是安培的千分之一),也就是 0.03 A。如果你提供的电流低于推荐值,LED 将不会很亮;如果电流过大,它可能会烧坏(当发生这种情况时,你会听到一声小爆炸)。这些信息通常也可以在 LED 的互联网清单或包装上找到。如果你不确定你的 LED 具体的参数,别担心——小巧便宜的 LED 通常都可以满足我们的需求。如果你没有任何关于 LED 的信息,可以假设其正向电压约为 2 V,正向电流约为 20 mA。
电阻器
为了避免 LED 过载,我们将使用一个 电阻器。每种材料都有电阻,而电阻器组件则专门设计用来在电路中产生纯粹的电阻。
LEDs 和大多数组件对通过它们的电流非常敏感。如果你将 LED 直接连接到电池并创建一个没有电阻的电路,LED 通过的电流可能会大到导致它过热。电阻器会降低 LED 中的电流,防止这种情况发生。
电阻器有不同的值,用彩色带表示,你可以在图 2-6 中看到。请查看第 202 页的电阻器指南,了解这些带子的含义以及如何读取它们。

图 2-6 一个电阻器
要找出你需要的电阻器,你需要应用欧姆定律!根据你之前看到的公式,你知道电阻等于电压除以电流,或R = V/I。在我们的例子中,电压是 Pi 提供的电压 3.3 V 与 LED 的正向电压之间的差值:即总电压减去LED 电压。对于我来说,就是 3.3 V – 3 V = 0.3 V。你应该使用你自己的正向电压,或者如果你不知道,可以用 2 V。
电流是 LED 的正向电流。对于我来说,这是 0.03 A。确保这个值是以安培为单位,而不是毫安!
注意
我建议购买一些电阻器,它们通常被组织成类似书本的形状。这样,你就会有适合各种情况的电阻器,而不必单独购买它们。
我可以通过简单地计算以下公式,算出我需要的电阻值,以将电流降低到 0.03 A:0.3 / 0.03 = 10。这意味着我需要一个大约 10 Ω的电阻。通常你不会找到一个电阻值正好等于你计算出的数值。没关系:在大多数情况下,你可以直接使用你能找到的最接近的电阻值。对于我的 LED,我很幸运,正好有一个与我所需值匹配的电阻。我正在使用图 2-6 中显示的 10 Ω电阻。
如果你仍然不确定你的 LED 的正向电压和正向电流,可以采取保守的做法,在电路中安装一个至少 100 Ω的合理大小的电阻。如果 LED 太暗,可以逐渐减小电阻,直到达到合适的亮度(足够暗以不伤害眼睛是一个好的经验法则)。不要尝试反过来做:你无法让 LED 复原!
跳线
最后,你需要一些电线来连接所有部件。具体来说,你需要跳线,这些是适合面包板使用的电线,允许你将元件连接到 Pi 的 GPIO 引脚。你可以在图 2-7 中看到一些跳线的示例。

图 2-7 一组跳线
跳线的两端可以是 公头 或 母头。公头端(通常缩写为 M)有一根突出的小线,可以插入面包板的孔中。母头端(缩写为 F)则有一个孔,可以将线插入其中。我建议购买各种类型的跳线,以便应对各种情况。我们在本书中将使用大量这些跳线!在 图 2-7 中,你可以看到我收集的 M-M、M-F 和 F-F 类型的跳线。为了让 LED 闪烁,我们需要两根 M-F 跳线。
连接 LED 的电路
现在你已经收集好了所有零件,是时候将 LED 接入电路并创建你的第一个电路了!你将按照 图 2-8 中所示的方式连接电路,因此可以在完成步骤时参考这个示意图。

图 2-8 用于连接 LED 的面包板示意图
根据你使用的面包板,电路的外观可能会略有不同。为了确保连接正确,请按照以下步骤操作:
-
将 LED 插入面包板,确保每根引脚位于不同的行中。如果将 LED 的引脚插入同一行,它们将相互连接,但不会连接到任何其他元件。LED 有正负极,必须按照电流的流向进行连接。LED 的长腿是正极——称为 阳极;短腿是负极——称为 阴极。LED 灯泡的阴极侧通常是平的,作为额外的标识。
-
将电阻的一端插入与 LED 短腿相同的面包板行中。将电阻的引脚放入与 LED 短腿相同的行中,即可将两者连接在电路中。将电阻的另一端连接到面包板上的任意其他点。
-
现在,确保树莓派关闭,将一根 M-F 跳线的公头端插入面包板,插入的位置应该与 LED 的长腿在同一行。找到树莓派上的物理引脚 7,也就是 GPIO/BCM 4 引脚(请参见 第 200 页 的“树莓派 GPIO 图”了解此引脚的图示),并将跳线的母头端连接到它。
GPIO 引脚的各种名称
树莓派的 GPIO 引脚有几种不同的名称。首先,你可以根据引脚的物理编号来参考它们——即它们的排列方式。然而,树莓派上的处理器并不理解这种编号方式,而是为 GPIO 引脚指定了自己的一套名称,这种编号方式通常称为 BCM 编号。以我们为例,你已经将 LED 连接到物理引脚 7:这实际上是 BCM 引脚 4!请参见 第 200 页 的“树莓派 GPIO 图”获取 GPIO 引脚的示意图及更多解释。
-
最后,将另一根 M-F 跳线的公头插入面包板中,只包含一个电阻引脚且不包含 LED 引脚的那一行。然后将母头连接到树莓派的物理引脚 6。这是一个接地引脚。你可以将接地看作是电池的负极端。它只是电压的低电位一侧。
编程你的树莓派来使你的 LED 闪烁
注意
当你开启树莓派时,LED 可能是关闭的、开启的,或者甚至微弱亮起。别担心!你的 LED 在这些状态下都没问题。你还没有指示引脚为某个特定状态,所以引脚现在还不确定该做什么。
现在你应该已经将电路连接好,启动树莓派并登录。是时候编写程序让 LED 闪烁了!
从终端,使用以下命令从主目录导航到你在第一章中创建的文件夹:
pi@raspberrypi:~ $ cd robot
现在你将创建一个新文件,并编写一个 Python 程序来控制你的 LED。你可以为文件选择任何你喜欢的名称,但确保文件名以.py结尾。我将它命名为blink.py。以下命令将创建一个新文件并打开 Nano 文本编辑器:
pi@raspberrypi:~/robot $ nano blink.py
你现在会看到一个与第一章中相同的 Nano 文本编辑器。
输入清单 2-1 中的代码,指示你的 LED 闪烁开关(圆圈中的数字在程序中并不会实际出现,但我们将用它们做参考)。
➊ import gpiozero
import time
➋ led = gpiozero.LED(4)
➌ while True:
➍ led.on()
➎ time.sleep(1)
➏ led.off()
➐ time.sleep(1)
清单 2-1 用于使 LED 闪烁的程序
这段八行的 Python 程序当你一行一行看时很容易理解,因此让我们逐行分析。
Python 是一种解释型编程语言,意味着当这段代码运行时,你的树莓派(或任何其他计算机)将按行执行程序,从顶部开始,按逻辑顺序逐行进行。这意味着代码的顺序很重要。
Python 自带了各种内建功能。例如,在第一章中,你打印了文本到终端,这是 Python 默认具备的功能。Python 还可以做成百上千的其他事情,但有些功能需要从外部源导入。例如,Python 本身不能控制你树莓派的 GPIO 引脚,所以我们导入了一个叫做 GPIO Zero 的库 ➊。在编程中,库是一个程序可以使用的函数集合。通过导入库,我们将这些函数带入当前程序供我们使用。GPIO Zero 库是由树莓派基金会创建的,目的是为程序员提供一个简单的 GPIO 接口。导入这个库使你的程序能够控制树莓派的 GPIO 引脚!请注意,尽管在编程语言中它实际上叫做gpiozero,因为我们不能在库名中使用空格,而且惯例是使用小写字母。
在下一行,我们导入了 time 库,它允许你的 Python 程序控制时间。例如,你可以暂停代码,这在我们的案例中非常有用!
接下来,我们创建一个变量 ➋。在编程中,变量是用于存储信息的名称,这些信息可以在程序中被引用和操作。它们提供了一种为数据贴标签的方式,使代码更简单、更易理解、更高效。
在这种情况下,我们创建了一个名为 led 的变量,引用了来自 GPIO Zero 库的 LED 软件。我们在括号中给 LED() 函数传入值 4,表示我们指的是 GPIO/BCM 引脚 4 上的 LED。当我们在程序中稍后调用 led 时,树莓派就知道我们指的是这个引脚。
然后我们开始一个 while 循环 ➌,这是一个 条件 语句,它会持续运行其中的代码,直到条件不再满足。用简单的语言来说,我们在告诉循环:只要条件为真,就继续运行代码。在这个例子中,条件就是 True。True 条件始终为真,永远不会为假,因此 while 循环将不断地循环下去。这对我们很有用,因为我们可以编写代码使 LED 闪烁一次,而循环会继续处理让 LED 不断闪烁的任务。
在 while 循环内部,你会遇到 Python 的一个关键结构特征:缩进。Python 知道,所有缩进相同数量空格的代码属于同一代码块,称为 块。while 循环后的四行代码每行缩进了四个空格;只要条件为真,循环就会运行整个代码块。
你可以通过不同的方式来创建缩进。有些人使用两个空格、四个空格或 TAB 键。你可以使用任何你喜欢的方法,只要在整个 Python 程序中保持一致。我个人喜欢使用 TAB 键。
在 ➍ 处,使用命令 led.on() 将 LED 打开。记住,led 是我们连接 LED 的引脚,现在我们在告诉那个引脚“开”。点号(.)将我们要操作的对象(此例中为 LED)与我们要求它执行的操作(此例中为打开)分开。打开 GPIO 引脚也叫做将引脚设置为 高电平,因为当这行代码运行时,树莓派会在电路中施加 3.3V 的电压。
接下来,我们使用 sleep() 语句 ➎ 来告诉程序暂停指定的秒数。在这个例子中,我们输入了 1,因此程序会暂停 1 秒。之后,使用命令 led.off() ➏ 将 LED 关闭。重复在 ➐ 处的 sleep() 语句,使程序在再次回到 while 循环的开始之前等待另一秒。这个开-等-关-等的过程将无限循环下去。
一旦你完成了程序代码的输入,可以退出 Nano 文本编辑器并保存你的工作。操作方法是按下 CTRL-X。然后会提示你是否保存你所做的更改。按下 Y 键表示保存。Nano 会提示你输入文件名,应该是blink.py,或者是你打开 Nano 编辑器时输入的文件名。按下 ENTER 键确认文件名。
运行你的程序:让你的 LED 闪烁
现在你已经理解了程序的工作原理,是时候运行它了。你将按照与在第一章中创建helloworld.py程序时相同的过程来执行程序。在树莓派的提示符下输入以下代码:
pi@raspberrypi:~/robot $ python3 blink.py
你的 LED 现在应该会按规律闪烁(见图 2-9)。恭喜你,你已经成功地将树莓派与外部世界连接起来!

图 2-9 一只高兴的闪烁 LED 连接到树莓派上
要停止你的程序并让 LED 停止闪烁,按下 CTRL-C。
故障排除指南:为什么 LED 不闪烁?
如果你的 LED 没有闪烁,不要惊慌。你可能通过一些故障排除就能修复电路。首先,检查一下你的 LED 是否正确插入。因为 LED 是一种二极管,电流只能朝一个方向流动,所以如果 LED 插反了,它就不会亮!它会什么也不做。回去查看说明,确保你按照要求正确连接了。
如果这没有解决你的问题,检查一下电路的其余部分。所有连接都正确吗?所有的电线都牢固吗?检查一下你是否将电路接到了树莓派 GPIO 端口的正确引脚上——这是一个很容易犯的错误!
如果你确信电路没有问题,并且你的 LED 和电阻是合适的(如零件列表中所述),那么可能是软件问题。当你运行程序时,它崩溃了吗?出现错误信息了吗?你可能在从本书中复制代码时犯了个错误。回去检查一下,或者从https://nostarch.com/raspirobots/获取代码文件,然后运行那里的blink.py文件。
GPIO Zero 库在所有新的 Raspbian 版本中默认包含,但如果你使用的是旧版本的 Raspbian,你可能需要手动安装该库。为此,输入以下命令:
pi@raspberrypi:~/robot $ sudo apt-get update
然后输入以下命令:
pi@raspberrypi:~/robot $ sudo apt-get install python3-gpiozero python-gpiozero
挑战自己:改变闪烁的时间
看一下你用来让 LED 闪烁的代码。如果你修改其中的一些代码,会发生什么呢?例如,你可以尝试改变sleep()语句的时间,看看能做出什么不同的模式!多试试,看看你的修改带来了哪些效果。
注意
如果你想关闭你的树莓派,应该先通过软件安全关闭,然后再拔掉电源线。要开始关机序列,使用命令**sudo shutdown now**。等几秒钟再拔掉电源线。如果你使用的是直接连接的显示器,也可以在图形界面的主菜单中选择关机选项。
按钮的输入:树莓派 GPIO 输入
让 LED 闪烁是进行树莓派电子学和物理计算的完美入门实验,但它只展示了树莓派 GPIO 引脚的输出功能。GPIO 引脚还可以接受输入,这意味着它们可以接收来自外部世界的数据并做出反应。在这一部分,你将为树莓派接上一个按钮,并编写一个程序,使其在按钮被按下时触发。
配件清单说明
本书中的项目是循序渐进的,因此,除了树莓派和面包板外,本项目还需要一个按钮和两根 M-F 跳线。
按钮有成百上千种不同的形状、大小和种类。在这个项目中,你需要获取一个适合面包板使用的瞬时按钮,就像图 2-10 所示的那样。

图 2-10 四脚瞬时按钮及其腿部对的示意图
按钮通常被称为开关,大多数按钮有两个或四个脚,连接到面包板的各个点。瞬时开关的功能很简单:当按钮被按下时,按钮内部的接触点会连接在一起,从而完成电路。当按钮松开时,内部的接触点会分开,电路就不再完整,电流也就无法流动。这意味着你的电路只有在按钮被按下时才会连接,这就是为什么它被称为“瞬时”的原因!
对于具有两个脚的按钮,当按钮被按下时,两个脚会连接在一起,这一点很明显。对于四脚按钮,情况就复杂一些。按钮的脚是成对排列的,因此你实际上只需要关心其中的两根。通常,像图 2-10 中所示的那样,按钮的对立两根脚是连接在一起的,这意味着每对中的一根脚只需要连接到电路上。如果你不确定哪些脚是成对的,请查看按钮的规格。
接线你的按钮
准备好配件后,你现在可以接线按钮了。请参考图 2-11 中的面包板示意图进行连接。

图 2-11 接线按钮的面包板示意图
如果你刚完成前一个项目并且仍然将 LED 连线到你的 Pi,可以随意拆开电路或将按钮接入面包板的不同部分——只要确保每个项目使用不同的面包板行。一旦准备好设置下一个电路,请按照以下说明操作:
-
将你的按钮插入面包板,并确保每个引脚都位于它自己的行中。你需要将按钮插入,使得两个引脚分别位于面包板中间行分隔器的两侧。
-
在 Raspberry Pi 关闭的情况下,使用跳线将分隔器一侧的一个引脚连接到 Raspberry Pi 上的地线引脚(物理引脚 6)。
-
使用另一根跳线将分隔器同一侧的另一个引脚连接到 Raspberry Pi 上的引脚 11(BCM 引脚 17)。如果你不确定哪个引脚是哪个,可以查看第 201 页的引脚图。
在你的 Pi 设置与图 2-12 中的我的设置相同的情况下,现在你需要编写一个程序,当按钮被按下时,从按钮获取输入。

图 2-12 完整的按钮和面包板设置
警告
完成后,你应该会有一个像图 2-11 中所示的电路设置。请确保接线正确。开关的电阻非常小,它会非常紧密地连接两个电路。错误的连接可能会对你的 Pi 造成危险!
编程你的 Raspberry Pi 以显示按钮的输入
从终端中,确保你处于第一章中创建的文件夹。 如果你刚完成之前的迷你项目,你很可能已经处于该文件夹中,但如果不是,可以使用以下命令从主目录进入robot目录:
pi@raspberrypi:~ $ cd robot
现在创建一个新的 Python 程序,以便从 Nano 中的按钮获取输入。我创建了一个名为button.py的程序,如下所示:
pi@raspberrypi:~ $ cd robot
你会看到一个熟悉的空白 Nano 界面。输入清单 2-2 中的代码,来使你的按钮正常工作。
➊ import gpiozero
➋ button = gpiozero.Button(17)
while True:
➌ if button.is_pressed:
➍ print("Button is pressed!")
➎ else:
print("Button is not pressed!")
清单 2-2 获取按钮输入的程序
我们以与闪烁 LED 项目 ➊ 完全相同的方式导入 GPIO Zero 库。本书中的所有电子项目都会使用此库,所以你可以在本书中的所有程序中看到这一行!
然后我们创建一个名为button的变量 ➋,将来自 GPIO Zero 库的按钮软件分配给该变量,并确保在括号中指定按钮连接到 BCM 引脚 17。
然后,我们像在 LED 程序中那样开始一个while循环,但与之前的程序不同,这个代码块中的第一行是一个if/else语句。在编程中,if语句是条件语句,当满足某个条件时激活某段代码。我们的if语句几乎可以直接翻译为英文“如果按钮被按下,执行以下操作” ➌。当if语句为真时,缩进的行 ➍ 会被执行,并在终端打印一串文本,告诉我们按钮已被按下。
通常,虽然不是总是如此,当有条件的if语句时,通常会有一个else语句,因为如果按钮没有被按下,必须发生某些其他事情!else语句 ➎ 可以翻译为英文“如果发生其他情况,执行以下操作。”然后,else语句后的缩进代码块被执行,并在终端打印出按钮没有被按下。
因为if/else语句位于一个条件为True的while循环中,所以代码会无限运行,除非程序被停止。一旦完成输入程序,你可以像平常一样退出 Nano 文本编辑器:按 CTRL+X,在提示符下按 Y 键保存更改,然后按 ENTER 确认文件名为button.py。
运行你的程序:获取来自按钮的输入
要运行你的程序,只需在终端输入以下内容:
pi@raspberrypi:~/robot $ python3 button.py
你现在应该会看到“按钮没有被按下!”这一语句在终端中反复出现。当你按下按钮时,“按钮已被按下!”的语句应当被打印到终端。
pi@raspberrypi:~/robot $ python3 button.py
按钮没有被按下!
按钮没有被按下!
按钮已被按下!
故障排除指南:为什么按钮没有工作?
就像在之前的迷你项目中一样,如果你的按钮没有工作,不要担心!首先检查电路。所有接线正确吗?电线牢固地插入了面包板吗?你把按钮接对了吗?如果你的开关与我的型号稍有不同,你是否查看了它与我模型的差异?如果你认为电路没有问题,可能是你在从本书复制代码时犯了错误。回去检查,或者从nostarch.com/raspirobots/下载代码文件。
要终止你的程序,请按 CTRL-C。
挑战自己:将按钮和 LED 程序结合起来
看看你能否将本章中的两个迷你项目结合起来。尝试创建一个程序,当按住按钮时闪烁 LED,或者一个程序,直到按钮被按下,LED 保持开启。
总结
在这一章,你通过两个小项目初步接触了电子学。你学到了很多理论和基础知识,这些都将在接下来的章节中帮助你构建机器人。我还介绍了一些关键的编程技巧和概念——未来我们会大量使用if/else语句和循环。
在下一章,我将带你完成制作第一个机器人的过程。我们将涵盖你需要的材料和工具,以及具体的构建过程。
第三章:构建你的机器人
机器人有各种形状、尺寸和设计,几乎能满足你能想象的所有需求——从国际空间站上的机械臂到为娱乐而设计的玩具机器人。
机器人可以根据特定任务进行定制,但要做到这一点,首先你需要了解并构建机器人的基本组件。在本章中,我将向你展示如何制作基本的机器人,你将基于它进行修改和改进,直到本书的最后。编程完成后,这个机器人将能够根据你的指令移动。在后续章节中,我们将为你的机器人添加传感器、灯光和摄像头,使其更加炫酷和智能!
你的第一个机器人
移动的机器人可以分为两大类:有轮子的和没有轮子的。没有轮子的通常是类人型,即具有两条腿并且类似人类,或者是基于动物的,比如狗(参见图 3-1 中的一些示例)。这些机器人通常非常难以制作和编程,因为构建者需要考虑平衡、运动以及许多其他因素。

图 3-1 来自波士顿动力的机器人
相比之下,使用轮子(或履带)的机器人占据了现实世界中机器人应用的大部分,它们没有复杂的平衡问题,因此非常适合像我们这样的爱好者和创客。一个著名的轮式机器人是 NASA 的好奇号漫游车,它有六个轮子,自 2012 年以来一直在火星上移动,进行着惊人的科学发现!
对于你的第一个机器人,你将制作一个如图 3-2 所示的双轮机器人。双轮机器人是机器人世界中的一个很好的起点。你的机器人将能够前进、后退,并通过每个轮子上的一个电机来实现左右转动。

图 3-2 我的完整树莓派机器人。到本章结束时,你也将拥有一个!
你将在本章中制作的这款双轮机器人具有完美的功能组合——它既经济实惠,又易于操作,且具有良好的机动性!
你将需要的材料
除了你的树莓派,你还需要一些其他的基本元件来组装你的机器人。就像创客世界中的所有事物一样,你可以根据可用的材料和组件进行选择,选择非常多。
如果这是你第一次使用树莓派和电子元件,我建议你使用我列出的相同配件,这样你就可以逐字按照说明操作。如果你有一些经验并且有自己的想法,那么可以自由探索;你不必坚持我推荐的内容。
面包板 我推荐使用一个 400 点的面包板,并且具有电源轨,就像第二章中使用的那种。
跳线 我推荐使用一套不同颜色和长度的面包板跳线。
底盘 这是机器人的身体,应该至少为 6 英寸 x 5.5 英寸。我正在使用乐高(请参阅下一个部分了解其他选项)。
两个有刷直流电机 使用 5V 至 9V、100mA 至 500mA 的电机,配有轮胎和集成齿轮箱。
电池盒 找一个可以容纳六节 AA 电池的电池盒。
六节 AA 电池 一次性电池或可充电电池都可以;我推荐松下的 Eneloop 可充电电池。
LM2596 降压转换器 这是一个降压电压转换器。
L293D 电机驱动器 这是一个集成的电机控制芯片。
你还需要各种螺丝刀、热熔胶枪、多用电表和焊接铁。
接下来的几个部分将提供有关每个组件及其功能的更多细节。如果你想直接跳到构建机器人的部分,请前往第 60 页。
底盘
底盘是机器人的基础框架,你可以把它看作机器人的“身体”。底盘构成了你将安装树莓派和其他部件的平台。
你可以使用多种不同的材料制作你的底盘,但无论你设计什么,底盘需要满足以下三个标准。底盘需要:
一个强大而稳定的平台 所有机器人的电子元件都将安装在底盘上,因此你需要确保它不脆弱。
至少 6 英寸 x 5.5 英寸 随着你在本书中的进展,你将向你的作品中添加越来越多的组件,因此你需要为扩展预留空间。不要担心让你的机器人底盘变得庞大,但也要确保它不至于太小!
易于修改 拥有一个易于修改、扩展和更改的底盘意味着你将来可以对你的机器人进行更多的定制!
乐高是我为初次构建机器人所偏好的材料。每个人都喜爱的积木能够制作出完美的机器人底盘。借助种类繁多且易于获取的积木和配件,你可以轻松地用乐高零件制作各种形状和大小的底盘设计。在本章中,我将展示如何使用图 3-3 中的零件来构建我的底盘。
硬纸板是另一个不错的选择,因为你可以随处获得它,且容易加工。一些简单的裁剪、折叠和粘合即可将硬纸板制作成各种底盘形状。卡纸越厚越好!你可以用任何回收的纸箱制作一个结实的纸板底盘——无论是鞋盒、亚马逊包装盒,还是麦片盒,都可以!

图 3-3 我用来制作机器人底盘的乐高零件,见图 3-2
如果你有一些简单的木工工具,比如木锯,那么用木材制作机器人底盘可能是个不错的主意。像松木和中密度纤维板(MDF)这样的廉价木材和木材复合材料,可以以低价制作出强固且稳定的底盘。
定制的塑料底盘可以成为一个外观不错的机器人基础。你可以以相对低廉的价格购买亚克力(Plexiglas、Lucite、Perspex)板,并用手锯或更好的带锯切割它们。更好的是,如果你能使用激光切割机,它能够根据计算机给定的精确尺寸和设计,制作出完美的机器人,就像你在图 3-4 中看到的那样。可以查看你所在地区是否有共享激光切割机的创客空间或黑客空间。

图 3-4 我在英国剑桥的创客空间设计并制作的定制激光切割机器人底盘
你还可以使用 3D 打印机处理塑料。3D 打印机通过加热并挤出塑料层,逐层构建物体。你可以在计算机辅助设计(CAD)软件中设计底盘,或者你也可以从互联网上下载并打印其他人的设计。随着 3D 打印机越来越普及,你可能会在本地图书馆、创客空间或黑客空间找到一个,或者你可能认识一个拥有 3D 打印机的人。
如果你不想自己制作底盘,你可以在网上购买各种基础套件。这些大多数是由一层或两层亚克力板组成,可以用螺丝和支柱将它们固定在一起(见图 3-5 中的示例)。你可以通过在互联网上搜索“机器人底盘”来找到预制底盘。eBay 通常有一些非常优惠的交易。

图 3-5 带电动机的预制底盘
电动机
没有电动机,你的机器人就不能移动。一个不能移动的机器人,谈不上是个机器人!让我们了解一些电动机的基础知识,这样你就能知道什么时候使用哪种电动机。
什么是电动机?
电动机将电能转换为机械能。电动机有各种不同的大小和设计,并且价格范围广泛。对于本书,你将需要购买两只(每只轮子一个)最便宜的电动机类型:直流电动机。这类电动机是最常见的,几乎所有设备里都有,从火车到台式风扇都可以找到它们。
DC 代表直流电,这意味着电流必须以一个方向通过电动机才能使其工作。直流电动机的替代品——例如交流电(AC)电动机和步进电动机——通常更贵、使用更复杂且电子学上更复杂,所以我们现在暂时使用直流电动机。
我们将使用的超简单电动机有两个端子。端子就是电流进出元件的点。当你在这些端子上施加电压时,电动机的轴会旋转。如果你改变电压的方向(有时称为反转电压),电动机会反向旋转。
你可以花越来越多的钱来购买更好的电动机。最好的做法是先从非常便宜的电动机开始,掌握基础,再投资更昂贵的设备。
电动机选项
对于第一次搭建机器人,选择一对有刷(非无刷)直流电机。在有刷和无刷电机中,电流会产生电磁力,推动电机轴旋转;然而,无刷电机更为复杂,并且需要额外的昂贵电路才能正常工作。无刷电机通常用于更为严肃的任务,比如遥控模型飞机和无人机。
你可以在任何常见的在线零售商处以不到 10 美元的价格购买一对有刷直流电机(可以查看“你应该在哪里买零件?”在 xix 页上的零售商列表)。购买之前,确保查看电机的规格。你需要考虑以下几个因素。
我建议选择额定电压在 5V 到 9V 之间的电机。如果电机的电压要求过高,你将会很难为其提供足够的电力,并且可能需要更多的电池。如果电机的电压过低,电源提供的电压(参见下一节)可能会导致过热并损坏电机!
电机所需的电流也是非常重要的。需要更多电流时,电池消耗得会更快,电机的控制也会更加困难。另一方面,电流较少意味着电机功率较小,可能会在推动机器人时力不从心。尽量确保你的电机每个额定电流不超过 500 mA。电流过大会使我们稍后使用的电机控制器超载。
便宜的电机通常具有较高的转速(RPM),每分钟转动大约 1000 到 3000 次,对于小型机器人来说,这个速度太快了。在这些转速下,每个电机的扭矩非常小。扭矩是驱动力,扭矩越小,机器人在表面上移动时就会越吃力。为了解决这个问题,你的电机需要一个齿轮箱来降低转速并增加扭矩。原始转速与降速后转速之间的比例叫做减速比,48:1 是本项目的一个不错的减速比。在寻找电机时,确保你查找的是已经预装小型齿轮箱的电机,可以使用“有齿轮的爱好电机”作为关键词。
没有轮子的电机是没用的。大多数电机会有一个轴,你可以将轮胎安装到上面,当电机运转时,轴会转动并推动轮胎。如果你购买的是没有轮胎的电机,你将需要找到适合电机轴的轮胎,这可能会有些困难。我建议购买带轮胎的电机。抓地力强的橡胶轮胎会让你更好地控制机器人。或者,你也可以尝试自己制作轮子,尤其是当你有 3D 打印机等精密设备时。
我使用的电机,见 图 3-6,符合所有这些标准。这些是常见的爱好者电机,配有齿轮箱和轮胎。它们的工作电压范围从 3 V 到 9 V,每个电机的电流大约为 100 mA。你可以以低至 $5 的价格购买一对。我是通过在 eBay 上搜索“机器人电机带轮胎”找到的,但在其他许多地方也能广泛购买到。

图 3-6 我的机器人电机和轮胎
大多数直流电机在出厂时不会附带连接到两个端子的电线。如果你的电机是这种情况,你需要焊接电线到电机上。焊接是通过将一种叫做焊料的填充金属熔化并将其放置在两个部件之间,来将两个部件电气连接在一起的过程。刚开始可能会觉得非常难,但别担心——它其实非常简单,而且是一个超级重要的技能!更多信息请查看 第 204 页的“如何焊接”。
如果你真的想避免焊接,你可能能在线找到已经焊接并连接到端子的电机。只要记住,这些电机可能很难找到,而且价格可能会更高!
电池
为了确保我们的机器人能够自行移动,我们将使用电池供电,这样就不会有拖动的电源线。电池是一种储存能量的电化学装置。
在本书中,你将使用 AA 电池为机器人供电。它们不仅常见且便宜,而且安全易用。单颗 AA 电池通常提供 1.2 V 到 1.5 V 之间的电压,并且可以串联在一起提供更高的电压。你需要的 AA 电池数量取决于电机的电压。六颗 AA 电池串联在电池盒中将提供 7 V 到 9 V 之间的输出电压,这应该是适合你机器人的电压。
AA 电池有两种类型:一次性(不可充电)和可充电电池。一次性电池较便宜,但只能使用一次,使用后需要负责任地丢弃。这意味着,随着时间的推移,使用一次性电池的成本会逐渐增加。我建议投资一些高质量的可充电电池和一款不错的充电器。初期开销可能较高($20–$30),但从长远来看,你会节省资金并且更环保!我使用的是松下的 Eneloop 可充电 AA 电池,见 图 3-7。请记住,可充电电池的电压通常比一次性电池稍低(AA 电池通常为 1.2 V,而非 1.5 V)。
为了存放并连接这些电池,你需要一个电池座。它不仅可以固定电池,还能将电池的端子连接起来,使得你只需要一根正极线和一根负极线即可从所有电池中获取电源。这些电池座在网上有很多售卖。我从 eBay 购买了一个带开关的六节 AA 电池座,价格为 1 美元,如图 3-7 所示。

图 3-7 我带有六节 AA Eneloop 可充电电池的电池座
电压调节器
警告
一些降压转换器需要电压“头部裕量”才能正常工作。例如,我使用的 LM2596 模块要求输入电压比输出电压高至少 2V。这意味着,在最坏的情况下,我的 LM2596 模块的最大输出电压为 7.2V – 2V = 5.2V。当我使用六节 AA 电池(提供 7V 到 9V 电压)时这不是问题,但如果我使用四节 AA 电池(仅提供 6V),我可能无法获得 5V 输出,从而无法为 Raspberry Pi 提供足够的电力。如果你使用的是不同的降压转换器,务必检查其网上清单或数据手册以获取详细信息。
尽管你的电动机可以愉快地使用电池提供的 7V 到 9V 电压运行,但你的 Raspberry Pi 肯定无法启动。你的 Raspberry Pi 严格依赖 5V 电压(容忍范围为±0.1 伏)。如果电压过低,Pi 将无法启动。如果电压过高,你的 Pi 将被烧毁!提供过高的电压会导致过大的电流流过 Pi 的内部组件,最终使 Pi“爆炸”(实际上意味着处理器会冒出一缕蓝烟,并且不可逆转地损坏)。
为了避免让你的 Pi“爆炸”,你可以使用一种简单的电压调节组件,称为降压转换器,将 7V 到 9V 电压转换为 Pi 所需的 5V 电压。降压转换器将输入电压降低到所需的输出电压。我们将使用基于 LM2596 芯片的转换器,它已经被整合成一个易于使用的模块板,如图 3-8 所示。这个模块可以接受 4V 到 40V 之间的输入电压,并将其转换为 1V 到 35V 之间的任何电压。稍后我会在本章中向你展示如何将其设置为 5V,以便为 Raspberry Pi 提供电力。
你可以在网上购买一个 LM2596 模块,或者其他类似的降压转换器,价格仅为几美元。如果你决定使用其他型号,确保它能够持续输出至少 2A 的电流。这些信息应该可以在产品的清单或数据手册中找到,数据手册是详细描述组件技术特性的参考资料。同时注意,你应该购买一个带有螺丝接线端子的降压转换器——这样可以让事情更简单,也避免了更多的焊接工作。

图 3-8 一款 LM2596 降压转换模块
电机控制器
你的直流电机每个最大电流为 500 mA。相比之下,树莓派的 GPIO 引脚总共只能提供 20 到 50 mA 的电流。这意味着你的电机需要直接由单独的电池组供电。这并不是什么大问题,但这也意味着树莓派不会直接连接到电机,因此你需要一个电机控制器来作为电机、电源和树莓派之间的接口。电机控制器可以让你使用树莓派控制电机的开关,并调节电机的速度。
市面上有许多不同种类的电机控制器,且有各种各样的封装形式。你可以购买驱动芯片、模块板,甚至是HAT(官方树莓派硬件附加在顶部)。每种选择都有其优点和缺点。
在本书中,我将使用一种叫做集成电路(IC)的芯片,型号为 L293D。像我的 L293D 那样的适合面包板使用的 IC(见图 3-9)是一个小型黑色盒子,里面包含了一些微型化的电子元件,如电阻器、晶体管和电容器。你可以将 IC 的引脚插入面包板,并将它们连接起来,以提供额外的电路功能。L293D 可以完全控制最多两个独立的电机——非常适合你的第一个机器人!

图 3-9 一款 L293D 电机控制器芯片
如果你想了解更多关于 L293D 电机驱动芯片的详细功能,可以在网上搜索它的数据手册。你可以在线以不到 4 美元的价格购买一颗 L293D。
推荐工具
在机器人构建过程和本书的后续章节中,你将需要一些基本工具。这是你需要的所有工具的清单,以及一些可选的工具,虽然不是严格必要的,但可能会对你有所帮助:
-
多种螺丝刀
-
热熔胶枪
-
万用表
-
焊接铁
组装你的机器人
一旦你有了机器人所需的所有组件,就可以开始组装并接线了!如果你购买了我之前列出的相同组件,你可以完全按照我的说明操作。如果你购买或制作了稍有不同的组件,你可能需要发挥一些创造力,但以下的说明应该是一个非常好的指南,不管你拥有的零件是什么。
制作底盘
如前所述,我是用 LEGO 积木制作我的机器人底盘,因此这些说明将采用这种方式。
你可以使用 LEGO 积木以无限种方式和组合制作底盘。我的底盘非常简单,使用了如下零件,见图 3-10:
-
两块 8×16 的板
-
四块 2×8 的板
如果你想购买这些准确的 LEGO 积木并严格按照这个过程操作,可以使用“Pick A Brick”服务,访问*shop.lego.com/en-US/Pick-a-Brick/。在这里,你可以通过搜索元素 ID 来订购单个零件,构建你自己的定制创作。你需要以下零件:
-
两个 8×16 板,ID 4610353
-
四个 2×8 板,ID 303428

图 3-10 我用来构建底盘的乐高零件
将这些 ID 号码输入元素 ID 搜索框,你应该能找到它们。
值得注意的是,根据乐高官网的说明,你可能需要等待最多 10 个工作日才能收到你的零件!如果你选择使用乐高零件制作底盘,之后的构建过程中你还需要其他砖块,所以我建议你一次性订购所需的所有砖块。
8×16 板的尺寸非常适合分别安装树莓派和面包板。我在我的底盘上留了两个乐高板之间的空隙,这样方便将电线整齐地穿过。
按照我的设计,将两个 8×16 板放置在两个乐高钉子之间,然后在上面安装两个 2×8 板将较大的板固定在一起。将另外两个 2×8 板固定在底部,使其更加坚固,如图 3-11 所示。

图 3-11 完成的乐高底盘:右侧是由 2×8 板组成的接头的特写
这将把板子夹在一起,创建一个坚固稳定的平台。
安装电机
底盘构建完成后,你可以开始安装并接线各种组件,从电机开始。在将电机安装到机器人主体之前,确保电机的端子上已经焊接了电线!再次参考第 204 页上的《如何焊接》部分,了解如何操作。
你需要将电机安装到底盘的底部,确保车轮尽可能靠近车身的中心,这样可以让你的机器人拥有较小的转弯半径——意味着它能做更紧的转弯。我会给你一些固定电机的选择。无论你选择哪种方式,确保电机对齐并尽可能平行。不平行的电机会导致机器人行驶方向的冲突,可能会阻止机器人沿直线行驶。
永久选项:胶水
使用热胶枪或超级胶水粘合可以将电机牢固且永久地粘附在底盘上。这是我固定电机到底盘的首选方法,但在粘合前请三思,因为它是永久性的!确保你完全满意电机的位置再进行粘合。
如图 3-12 所示,胶水涂抹均匀可以确保电机连接牢固,不会晃动。

图 3-12 用热胶固定电机
较不永久的选项:魔术贴或螺丝
传统的魔术贴材料(更常见的名字是 Velcro)是一种非常好的方式,可以将物品非永久性地固定在一起,无需工具也不会弄得一团糟。我最喜欢的品牌是 3M Dual Lock,这是一种非常强力的魔术贴垫,虽然价格比其他解决方案稍贵,大约每米$15。魔术贴通常有一个粘性背面,所以你可以根据需要剪裁,撕开保护膜,然后将其粘贴到底盘上。如果你发现这不够牢固,或者对于安装电机来说太灵活,我建议在 Velcro/Dual Lock 的边缘加一点胶水。
另外,一个不那么永久性的选择是使用螺丝。如果你做了一个木质、激光切割的塑料或 3D 打印的底座,可以将电机用螺丝固定到底盘上。有些电机甚至自带支架和螺丝,专为此目的设计。这是一种稳固的方式,而且你可以随时卸下电机,用于其他项目。
更不永久的选项:胶带
双面胶带适用于轻松、无麻烦地固定零件,类似于魔术贴,尽管这是最弱的选择。
稳定机器人
在将电机固定到底盘底部后,将每个电机的两根电线通过缝隙引导到平台顶部,如图 3-13 所示。

图 3-13 电机连接的底盘,电线通过缝隙引导
当你的两个电机固定在机器人底盘的中央时,你可能会发现平台不稳定,并且重心偏向较重的一侧。别担心:你可以轻松修复这个问题!
稳定器可以防止你的机器人摇晃,并确保平稳移动。每侧只需要一个稳定器,它可以由任何材料制作。由于我使用的是 LEGO 底盘,我的稳定器是用 LEGO 积木做的!我在机器人前后底部各放了两个五层深的 2×4 积木柱子;这些柱子会稳定重量,但不会接触地面,所以在平滑表面上运行时,它们不应阻碍运动。这些导轨已经完全消除了摇晃;见图 3-14。

图 3-14 带有 LEGO 稳定器的底盘,位于前后底部
如果你还使用 LEGO 零件,可能需要更多或更少的积木——只需确保你的稳定器从底盘底部延伸到离地面略高的位置。小心不要让稳定器太长,因为它们可能会妨碍机器人运动,或者完全将电机悬空!
如果你不想用 LEGO 积木做稳定器,你可以使用任何其他材料(如塑料片、木材等),只要它能放置在底盘和地面之间,并且能够牢固地固定到你的底盘上。
一个常见的选择是使用一个或两个万向轮或球;这些是非电动的轮子或球,专门用于平衡机器人。你应该能在网上找到合适尺寸的产品——只需测量底盘到地面的距离(当底盘保持水平时),你通常还会发现这些万向轮带有螺丝安装孔,这使得它们特别适合用在木质或塑料底盘上。
你可以在线购买的许多机器人平台通常是完整套件,包含电机、轮子和万向轮。这是节省时间的好方法,特别是当所有的孔位都已经为你钻好时。
安装电池
现在你已经将电机安装到机器人上,可以固定电池盒和电池了。确定电池的安装位置需要考虑两个关键因素:
空间 你的电池盒需要多少空间?电池盒的线缆能否连接到底盘顶部?电池盒会妨碍机器人运动吗?
访问 在某些时候,你需要拆卸电池并进行更换或充电,因此你需要确保电池盒的位置便于访问。不要犯将电池盒永久粘贴上去的错误,之后却无法取出电池!
警告
确保在电池安装时,电池盒的正负极线不会意外接触。如果接触了,会导致短路,进而引起快速加热,甚至可能损坏电池。
我将我的电池包安装在 LEGO 底盘的底部,并置于电机之间,如图 3-15 所示。这是一个不错的选择,因为它使得顶部可以留空,以便安装你需要更频繁访问的组件,比如树莓派,同时仍能方便地更换电池。我使用了可靠的 3M Dual Lock 将电池盒固定到位。尽量将电池盒安装在中心位置,以保持平衡。

图 3-15 安装了电池盒的机器人底部
一旦将电池盒固定好,就可以将新电池或充满电的电池插入,并将电池盒的线缆穿过底盘顶部。
安装树莓派、面包板和降压转换器
在安装好电机和电池后,将机器人翻转至正确的位置,安装关键电子组件:你的树莓派、面包板和降压转换器。
8×16 LEGO 板的尺寸完美适配一个树莓派和一个面包板。正如你在图 3-16 中看到的,我将树莓派安装在一个板上,面包板安装在另一个板上。在右下角,你还可以看到 LM2596 降压转换器。这是我推荐的部件布置方式。

图 3-16 安装了树莓派、LM2596 和面包板的底盘
由于你可能还想再次使用你的 Pi,我建议使用一种非永久性的粘合剂。我使用了粘性粘土小心且非永久性地固定了我的 Pi。大多数面包板都配有粘性背面,所以我只是撕下了背面的保护膜,利用粘合剂将面包板牢固地固定在 LEGO 板上。如果你的面包板没有粘合背面,那么我也建议你使用粘性粘土来固定它。
根据你的外壳材质,你可以选择不同的方式来固定你的电子设备。最新的树莓派及其早期型号都有螺丝孔,因此你可以使用一组小螺丝将树莓派固定到木质或塑料外壳上。
我将 LM2596 降压转换器模块使用更多的粘性粘土固定在面包板旁边,并通过两个 2×2 的 LEGO 积木将其悬挂起来。当你这样做时,确保电压调节器的螺丝端子可以轻松访问,并且不被面包板或其他物品阻挡,因为稍后你需要连接电线到这些端子。
为树莓派接入电源
在你为电动机接线之前,你需要为机器人大脑——树莓派——提供电源。
如前所述,确保你的 Pi 获得 5V(±0.1V)的电压至关重要,而不是你电池提供的 7V 或 9V(或其他电压)。这意味着你需要调整降压转换器,使其输出精确的 5V 电压。
最好的方法是借助一种叫做万用表的工具,如图 3-17 所示。你应该能在线以低至$10 的价格购买一台万用表。

图 3-17 万用表,设置为读取电压
万用表是一种电子测量仪器。普通万用表可以测量电压、电流和电阻。我们需要测量的是电压。
一些电压转换器,比如我正在使用的 LM2596 模块,确实配有一个小 LED 屏幕,可以显示电压读数。理论上,这样就不需要使用万用表,但仍然建议使用万用表来再次检查输出电压。万用表将来也会派上用场,所以这是一项明智的投资。
我们将通过 Pi 的 GPIO 引脚连接电源。按照这些说明小心操作,慢慢来,你的 Pi 将会安全供电,不会烧坏!但不要太担心:这种为 Pi 供电的方法已经经过多次测试,正确操作的话完全是安全的!
设置转换器
首先按照以下说明设置你的降压转换器——此时你还不需要将它连接到树莓派。翻到图 3-21 查看降压转换器设置的最终电路图。你还可以查看图 3-19 中的降压转换器特写图像。
-
将电池组的两根电线分别连接到面包板的不同列和行上。大多数面包板的两边都有两排带红色和蓝色线的电源轨,或者末端标有+或-符号;这些电源轨被称为电源轨。为了帮助区分负电源和正电源线的位置,将电池组的黑色(负)电线连接到面包板蓝色负电源轨的一侧,将红色(正)电线连接到该侧的红色正电源轨。请查看图 2-4 在第 34 页上的电源轨示意图。
电池组 面包板 红色,正电线 正电源轨 黑色,负电线 负电源轨 现在我们来连接 LM2596 模块。大多数 LM2596 降压转换器模块都配有十字螺丝端子。要连接电线,只需松开你需要连接的端子,将电线插入前面的孔中,然后拧紧螺丝以确保连接牢固。
-
取一根红色和一根黑色的 M-M 跳线,将它们分别插入正负电源轨。确保电线的两端在此过程中不会接触到。现在,松开 LM2596 模块上标有 VIN(输入电压)的端子螺丝,将红色的正电线插入,并拧紧螺丝。然后,将黑色的负电线插入 LM2596 模块同一侧标有 GND(接地)的端子,如图 3-18 所示。确保正负电源线连接正确!!image
图 3-18 7 V–9 V 和接地线路接入 LM2596 降压转换器
LM2596 连接 VIN 红色电线,正电源轨 GND 黑色电线,负电源轨 -
接下来,打开万用表并将其设置为测量电压——大多数万用表可以通过旋转中间的旋钮到V来完成。然后将万用表的红色正表笔插入降压转换器的 VOUT(输出电压)端子,将万用表的黑色负表笔插入同一侧的 GND 端子(见图 3-19)。你应该能在万用表上看到降压转换器的输出电压读数。暂时不用担心读数的具体数值!!Image
图 3-19 降压转换器的特写
-
当万用表连接好并且你可以看到电压的变化时,使用螺丝刀旋转降压转换器顶部的调节螺丝(参见 图 3-19)。插入螺丝刀后,不论是向左还是向右旋转,电压读数应该会发生变化。找出正确的旋转方向,然后继续旋转螺丝,直到万用表显示 5 V(±0.1 V),如 图 3-20 所示。这需要一些反复试验!image
图 3-20 万用表显示降压转换器输出 5 V
注意
略微过载 Raspberry Pi,使用不超过 5.1 V 的电压是有益的。这样可以防止由于电池在电动机运行时出现小幅电压下降,导致 Pi 停机。
-
一旦你确认万用表显示 5 V(±0.1 V),拔掉万用表并关闭电源。
连接转换器
现在你已经调整了降压转换器的输出电压,可以将它连接到你的 Raspberry Pi 上。在接线之前,请确保电池关闭,或者甚至将电池从电池座中取出。
-
拿两根 M-F 跳线——通常的规范是使用一根红色表示正极,一根黑色表示负极(接地)。你将跳线的公头连接到降压转换器的输出端子。像往常一样,将红线连接到正输出端(VOUT),黑线连接到负输出端(GND)上 LM2596 模块的输出端。然后,将红线连接到 Raspberry Pi 的物理引脚 2(+5 V)。最后,将地线连接到 Raspberry Pi 的物理引脚 6(接地)。参见 图 3-21 了解面包板电路图和显示 Pi 应该如何接线的图片。也可以参考 “Raspberry Pi GPIO 图解” 第 200 页。


图 3-21 降压转换器电路的面包板示意图(上);已接线的 LM2596 转换器(下)
警告
在继续之前,请仔细检查你对接线和降压转换器提供的电压是否满意。如果你有任何疑问,拔掉 Pi 并使用万用表再次检查电压,然后再开机。多检查几次总是没错的!
做得好——你已经成功将降压转换器接入 Pi 的 GPIO 引脚!现在打开电池座的电源开关(或者重新插入电池),你应该会看到你的 Raspberry Pi 像连接了微型 USB 端口一样启动。
连接电动机
你构建基础机器人时的最后一步是将电动机连接到电动机控制器,然后再将电动机控制器接入 Pi。请注意,如果你使用的是与我不同的电动机控制器,过程可能会有所不同。
警告
在开始之前,请确保你的树莓派没有通电,并且电池盒中的电池已取出或关闭。当你接线时确保树莓派关闭非常重要,这样可以避免发生短路,防止损坏元件或树莓派。
连接 L293D 电机控制器
以下说明适用于我使用的 L293D 电机控制器芯片:
-
将 L293D 芯片牢固地插入面包板,确保所有引脚处于不同的行中,并且没有与其他元件连接。为此,将芯片放置在面包板中央的空隙上,如 图 3-22 所示。像 L293D 这样的集成电路的引脚通常不是完全笔直的,因此你可能会发现它不容易插入面包板。如果遇到这种情况,请拿起 L293D,并轻轻地将每一侧按压在平面上,将引脚弯曲成直角。
![image]()
图 3-22 插入面包板的 L293D
注意
你可能已经注意到,你在面包板上使用了两组电源轨道。一个电源轨道提供来自电池的+7 V 至 9 V 电压,而另一个电源轨道则提供来自树莓派的+5 V 电压。由于这种电压差异,务必仔细检查,确保你不会将元件或其他部件连接到错误的电源轨道!
-
L293D 有 16 个引脚,其中没有标注,因此你需要参考 图 3-23 中的引脚图来连接电机控制器。你通常也可以在芯片的数据手册中找到这些信息。集成电路的引脚编号是从左上角引脚开始逆时针排列的。L293D 的第 1 引脚位于芯片顶部缺口的左侧。有时芯片上也会有一个点,标示在第 1 引脚旁边。
-
L293D 需要独立的电源来工作,我们可以通过树莓派的 5 V 引脚提供电源。我们已经在使用第一个 5 V 引脚,因此使用一根 M-F 跳线将树莓派的第二个 5 V 引脚(物理引脚 4)连接到面包板边缘未使用的红色电源轨道。使用另一根 M-F 跳线将树莓派的一个地线引脚(物理引脚 9)连接到同一侧的蓝色电源轨道;参见 图 3-24。确保你没有将任何东西连接到之前已接线的电源轨道!
![image]()
图 3-23 L293D 的引脚图
-
现在我们将连接两个电源轨道的地线。用一根黑色的 M-M 电线将面包板上的两个蓝色电源轨道连接起来,这样就连接了树莓派的地线轨道和电池的地线轨道,如 图 3-24 所示。我们将连接的地线称为 共地。
![image]()
图 3-24 插入面包板的 L293D 芯片,并且树莓派的电源轨道已连接
-
接下来,使用一根线将 L293D 的引脚 16(VCC 1)连接到 5 V 正电源轨(连接到树莓派的 5 V 引脚)。这就是芯片的电源。完成后,将 L293D 上的地线引脚(GND),即引脚 4、5、12 和 13,连接到公共地线。有关连接的具体信息,请参考图 3-25 中的面包板示意图。
![image]()
图 3-25 5 V 电源连接到 L293D,并且所有四个地线已连接
注意
跳线的长度有时会让它们变得笨重,导致接线看起来混乱。如果你购买了多种尺寸的面包板跳线,可以选择较短的跳线来让面包板看起来更加整洁。或者,购买一些单芯线,自行裁剪并剥线来调整合适的长度。
-
现在是时候连接电机的电源了,它将直接来自你的电池组。将 +7 V 到 9 V 的正电源轨(连接到你的电池组)连接到 L293D 的引脚 8(VCC 2)。与之前不同,这次这是电机的电源,而不是芯片的电源。图 3-26 显示了这个连接。
-
L293D 有两个 使能 引脚。如果这些引脚没有 打开(也就是说,它们没有接收到高电压),那么连接到 L293D 的任何电机都不会响应命令。要永久打开使能引脚,将 L293D 的引脚 1(使能 1,2)和引脚 9(使能 3,4)连接到树莓派 5 V 正电源轨。我在图 3-26 中使用了白色的跳线来演示这一步骤。
![Image]()
图 3-26 通过将 L293D 的使能引脚连接到树莓派的 5 V 电源轨来给其提供高电压
连接电机
现在你可以将电机接到 L293D 上了。
-
取一个电机,将其一根电线连接到 L293D 芯片的引脚 3(输出 1),另一根电线连接到引脚 6(输出 2)。然后取第二个电机,将其两根电线中的第一根连接到引脚 11(输出 3),第二根连接到引脚 14(输出 4),如图 3-27 所示。
![image]()
图 3-27 两个电机连接到 L293D 的输出端
完成接线
接线过程的最后阶段是将树莓派的 GPIO 引脚连接到 L293D 的输入端。每个电机需要两个 GPIO 引脚才能工作(我将在下一章中讲解它是如何工作的)。这意味着,驱动两个电机,你总共需要四个 GPIO 引脚。
-
使用 M-F 跳线将你的树莓派物理引脚 11(BCM 17)连接到 L293D 的引脚 2(输入 1)。然后使用另一根跳线将树莓派的物理引脚 12(BCM 18)连接到 L293D 的引脚 7(输入 2)。现在,你已经成功地接上了一个电机。此时,你的面包板应该像图 3-28 所示,最新添加的部分是粉色的线。
![image]()
图 3-28 第一个电机的输入控制引脚从树莓派连接到 L293D
-
最后,你必须为第二个电机接上 GPIO 引脚。通过将 Pi 的物理引脚 13(BCM 27)连接到 L293D 的引脚 10(输入 3)来完成此操作。然后将 Pi 的物理引脚 15(BCM 22)连接到 L293D 的引脚 15(输入 4)。
恭喜!你已经完成了电机和电机控制器的接线。你的面包板应该像图 3-29 中的示意图一样,其中最后的接线以紫色显示。此外,图中还展示了我已经接好线的机器人照片。


图 3-29 完整电路,两个电机的输入线从 Pi 连接到 L293D(上图);完成的机器人!(下图)
你已经完成了第一个机器人的物理部分。下一步是编程,让它做一些酷炫的事情。目前,你可以将你的机器人编程成像遥控车一样移动。在下个章节中,我们将添加一些代码,让你能够实现这一功能!
自定义你的机器人
没有什么比乏味的机器人更糟糕了。现在你已经构建了底盘并接好了电子元件,为什么不为你的作品增添一些个性呢?添加一些颜色!装饰一下你的底盘!你可能会注意到,我的机器人上有各种各样的乐高小人正在骑行。
总结
你在这一章节中已经做了很多工作!我们讨论了为什么两轮机器人非常棒,它们的各种组成部分,以及你在构建它们时可以选择的选项。我已经向你展示了如何接好 Pi 的线路,连接电源,并将电机连接起来,从零开始构建属于你自己的机器人。
在所有这些基础工作完成后,在接下来的章节中,我将引导你进入下一个激动人心的步骤:编程你的机器人并让它动起来!
就像任何接线工作一样,稍微的坚持就能带来回报!在进入下一个章节之前,快速浏览一下说明,确保没有短路,并且所有连接都按预期连接。这样,你就能顺利地在下个章节中让机器人启动并运行。
第四章:让你的机器人动起来
在这一阶段,你有一个外观很酷的树莓派机器人,但它现在什么都做不了…… 还!为了充分发挥你刚接好线的所有硬件功能,你将不得不深入一些编程工作。
在这一章中,我将向你展示如何使用 Python 编程语言让你的机器人动起来。我们将涵盖基本运动、让机器人实现遥控以及调整电机的速度。
部件清单
本章的大部分内容将涉及如何编写代码来控制机器人,但为了实现遥控,你稍后需要一些配件:
-
任天堂 Wii 遥控器
-
如果你使用的是比 Pi 3 或 Zero W 更早的版本,可能需要使用蓝牙加密狗
理解 H-桥
大多数单电机控制器都基于一种叫做 H-桥 的电子概念。我们使用的 L293D 电机驱动芯片包含两个 H-桥,允许通过一个芯片控制机器人上的两个电机。
H-桥是一个电子电路,允许在负载(通常是电机)上施加电压,且电压方向可以是任意的。对于机器人应用而言,这意味着 H-桥电路可以驱动电机 正转 和 反转。
单个 H-桥由四个电子开关组成,采用晶体管构建,像图 4-1 中的 S1、S2、S3 和 S4 那样排列。通过操作这些电子开关,H-桥控制单个电机的正反电压流动。

图 4-1 单个 H-桥电路
当所有开关都处于打开状态时,电机上不会施加电压,电机不会转动。当只有 S1 和 S4 闭合时,电流会在电机中一个方向流动,令电机旋转。当只有 S3 和 S2 闭合时,电流会在相反方向流动,使电机反向旋转。
L293D 的设计意味着我们不能同时关闭 S1 和 S2。幸运的是,若这样做会导致短路,从而损坏电路!S3 和 S4 也有相同的问题。
L293D 将这一概念进一步抽象化,只需两个输入控制一个电机(对于一对电机,则需要四个输入,像你在第三章中接线的那样)。电机的行为取决于哪些输入为高电平,哪些为低电平(分别为 1 和 0)。表 4-1 总结了控制一个电机的不同输入选项。
表 4-1 基于输入的电机行为
| 输入 1 | 输入 2 | 电机行为 |
|---|---|---|
| 0 | 0 | 电机关闭 |
| 0 | 1 | 电机朝一个方向旋转 |
| 1 | 0 | 电机朝另一个方向旋转 |
| 1 | 1 | 电机关闭 |
我们将使用 GPIO Zero Python 库与 Pi 的 GPIO 引脚和电机控制器进行接口。该库中有几个函数用于控制基本运动,因此你不必担心自己手动开启或关闭特定的 GPIO 引脚。
第一次运动
现在,进入你的机器人旅程中最激动人心的一步:让机器人动起来!你最终会让机器人完全遥控,甚至能够根据你的指令行动,但在那之前,先掌握一些基本的电机功能。你将从编程让机器人沿预定路线移动开始。
用预定路线编程你的机器人
启动你的 Raspberry Pi 并通过 SSH 登录到你的机器人。 当机器人保持静止并进行编程时,最好断开电池连接,通过连接到墙壁插座的 micro USB 电缆为 Pi 供电。这样可以节省电池,等到真正需要时再使用。
从终端中,导航到你的主目录下存储代码的文件夹。对我来说,我将导航到我的robot项目文件夹,命令如下:
pi@raspberrypi:~ $ cd robot
接下来,创建一个新的 Python 程序,并使用以下命令在 Nano 文本编辑器中编辑它;我将我的程序命名为 first_move.py:
pi@raspberrypi:~/robot $ nano first_move.py
现在你需要为编程制定一个预定的路线!对于我们使用的直流电机,你无法让它们转动特定的距离或步数,但你可以通过开关电源来控制它们运行一定时间。这意味着任何路径都将是你希望机器人走向的粗略近似,而不是精确的计划。
首先,让我们简化一点,让你的机器人在方形路线内行驶,路线如下所示 图 4-2。

图 4-2 机器人计划的路线
在你的 first_move.py 文件中,输入 列表 4-1 中的代码来编程一个方形路线。
import gpiozero
import time
➊ robot = gpiozero.Robot(left=(17,18), right=(27,22))
➋ for i in range(4):
➌ robot.forward()
➍ time.sleep(0.5)
➎ robot.right()
➏ time.sleep(0.25)
列表 4-1 编程让你的机器人沿方形路径移动
程序首先导入常用的 Python 库:gpiozero 和 time。然后你创建一个名为 robot 的变量 ➊,并为其分配来自 GPIO Zero 库的 Robot 对象。
在 Python 中,对象 是一种将变量(信息片段)和函数(执行任务的预定义指令集)保存在一个实体中的方式。这意味着,当我们将一个对象分配给一个变量时,该变量将拥有一系列预定义的功能和操作。对象通过它的类来获得这些功能。每个类都有自己的函数(称为方法)和变量(称为属性)。这些是 Python 的高级功能,你在这个阶段不需要太多担心它们。只需要知道,我们正在使用来自 Python 库的预定义类,比如 GPIO Zero,这样可以让我们的编程变得更容易。
GPIO Zero 库内置了一个Robot类,提供了多种用于让双轮机器人朝不同方向移动的功能。请注意括号中的两组值,它们分别分配给left和right ➊。这些值代表你连接到 L293D 的输入引脚。如果你按照第三章中的接线方式进行操作,那么这四个 GPIO 引脚应该是:17、18、27、22。
该程序还使用了一种新的循环类型,称为for循环➋。在第二章中,当你让 LED 灯闪烁并从按钮获取输入时,你使用了while循环。while循环会在满足某个条件时无限期地重复其内容,而for循环则是将一段代码块重复执行固定的次数。该循环的语法for i in range(4):意味着“做以下事情四次”。
for循环指示你的机器人开始向前行进➌,然后等待半秒钟 ➍,以便给机器人一些时间进行移动。结果是两个电机在一个方向(前进)上移动了半秒钟。
接着,你指示机器人向右转➎,并在此过程中等待四分之一秒 ➏。通过让机器人向右转,你将半秒前发出的前进命令替换为新的电机指令。
一旦执行完成,“向前走然后右转”的过程会重新开始,并持续四次。你尝试让机器人走一个方形路线,而方形有四条边,因此需要特定次数的重复。
一旦你完成编写程序,按 CTRL-X 退出 Nano 并保存你的工作。接下来,我们将运行程序让机器人开始移动!
GPIO Zero 的 Robot 类包含所有方向和基本功能的命令,详见表 4-2。
表 4-2 Robot类命令
| 命令 | 功能 |
|---|---|
robot.forward() |
让两个电机向前转动。 |
robot.backward() |
让两个电机后退。 |
robot.left() |
让右电机向前转动,左电机向后转动。 |
robot.right() |
让左电机前进,右电机后退。 |
robot.reverse() |
反转机器人的当前电机方向。例如:如果前进,则后退;如果向左,则向右。这不是后退! |
robot.stop() |
停止两个电机。 |
运行程序:让你的机器人移动
在执行程序之前,确保你的机器人已经从墙壁电源插座断开,电池已连接并开启。你还应该将机器人放置在一个相对较大、平坦的表面上,确保没有障碍物和危险。粗糙的表面,如地毯,可能导致你的机器人卡住或难以移动。尽量避免这种情况,因为电机困难时会消耗更多电流,而且当电机完全被阻止(或停滞)时,可能会损坏电子元件!表面越平坦,机器人运行得越顺畅。
让你的机器人处于一个能够“接住”它的位置也是个好主意,以防它或某个物体/某个人处于危险之中。例如,它可能会试图下楼梯,或者猫可能会挡住路。
要运行你的程序,通过 SSH 无线访问你的 Pi 的终端并输入:
pi@raspberrypi:~/robot $ python3 first_move.py
你的机器人应该开始动起来。如果一切顺利,它将沿着一个方形路径移动,然后停下来,程序也会自动结束。如果你需要在任何时候停止机器人,可以按键盘上的 CTRL-C 立即停止电机。
故障排除指南:机器人工作不正常?
如果你的机器人没有正常工作,不用担心。通常故障可以归类为一些常见问题,应该很容易解决!以下的快速指南将帮助你解决大部分可能遇到的问题。
机器人移动不稳定
执行 first_move.py 程序后最常见的问题是,机器人移动了,但不是按照正确的模式。例如,它本应前进,但却后退;或者它本应右转,但却左转。你甚至可能发现它只是原地旋转!
这种情况可以很容易修复。正如我们讨论过的,直流电机有两个端子,没有特定的极性。这意味着,如果你改变电流流动的方向,电机就会反向旋转。因此,如果一个或两个电机的转动方向与命令相反,你可以交换连接到电机控制器输出引脚的电线来反转方向。例如,交换连接到 L293D 输出 1 和输出 2 的电线。有关指导和相关图示,请参阅第三章。
电机不转动
如果你的程序成功执行,但机器人的轮子没有转动,或者只有一个电机开始转动,那么可能是你的接线出了问题。请回到上一章,检查你是否按照说明连接了所有设备。确保电机的连接牢固,没有任何电线松动。如果你确信接线正确,检查一下电池是否充满电,并且它们能为你的电机提供足够的电力。
如果你的 Raspberry Pi 在电机开始转动时崩溃,可能是电源出现了问题。检查你是如何设置降压转换器的。如果你使用的是与我不同的转换器,可能会遇到问题。请回到上一章获取指导和建议。
机器人移动非常缓慢
机器人运动缓慢通常意味着电机没有得到足够的电力。检查你的电机的电压要求,确保你提供了它们所需的电压。通常电机可以接受一范围的电压,例如从 3V 到 9V。如果你的电机支持这一范围,试着使用一个更高的电压,但要确保它仍然在推荐范围内。请记住,如果你更换了电池并且更改了电压,记得检查并重置降压转换器,确保你不会给树莓派提供超过 5.1V 的电压。
另外,电机本身也可能只有较慢的齿轮转速。如果是这种情况,虽然你的机器人可能会慢,但它可能有很大的扭矩,这是一个不错的权衡。
机器人没有按照编程路径行驶
如果你的机器人成功执行程序并开始以适当的速度移动,但没有精确按照你预定的路径行驶,不用担心!每个电机都是不同的,你需要进行一些调整才能让程序按你的需求运行。例如,0.25 秒可能不足以让电机让你的机器人大约转动 90 度。修改程序,调整for循环中的sleep()和robot()语句。
使你的机器人实现远程控制
让机器人“复活”并开始移动是机器人技术的一个令人兴奋的第一步,接下来的自然步骤就是让你的机器人实现远程控制。这意味着它不再局限于预定的路径,你将能够实时控制它!
这个项目的目的是编程你的机器人,使你能够用无线控制器来引导它。你将能够在不重新进入代码的情况下,瞬间改变机器人运动的方式。
Wiimote 无线控制器
为了用无线控制器控制你的机器人,首先你需要一个!我们机器人的完美遥控器是任天堂的 Wii 遥控器,也就是Wiimote,如图 4-3 所示。

图 4-3 我心爱的任天堂 Wiimote
警告
为了确保与你的树莓派兼容,请确保你的 Wiimote 是任天堂官方品牌的正品型号。近年来,许多第三方 Wiimote 已经上市。尽管通常比官方 Wiimote 便宜,但这些产品不能保证与cwiid库兼容。
Wiimote 是一个非常巧妙的小型蓝牙控制器,带有一组按钮和一些能够检测运动的传感器。Wiimote 最初是为任天堂 Wii 游戏机设计的,但幸运的是,有一个开源 Python 库,叫做cwiid,它允许像树莓派这样的 Linux 电脑与 Wiimote 连接并进行通信。我们将使用cwiid来操控 Wiimote 的数据,从而控制你的机器人的电机。
如果你还没有 Wiimote,你需要去购买一个。这些在线上广泛销售,既有新的,也有二手的。我建议在像 eBay 这样的网站或二手商店购买一个便宜的二手 Wiimote——我买的只花了不到 15 美元。
你将使用蓝牙将 Wiimote 与 Raspberry Pi 连接到你的机器人上。蓝牙是一种无线射频技术,许多现代设备,如智能手机,使用它来进行短距离的通信和数据传输。最新的 Raspberry Pi 型号,如 Pi Zero W 和 Raspberry Pi 3 Model B+,内置蓝牙功能。所有在 Raspberry Pi 3 Model B 之前的型号,如原始的 Raspberry Pi 和 Pi 2,都没有蓝牙功能,因此你需要获取一个蓝牙 USB 适配器(或适配器),如图 4-4 所示,用于连接 Wiimote。

图 4-4 一款 3 美元的 Raspberry Pi 兼容蓝牙适配器
这些在网上售价不到 5 美元;只需搜索“Raspberry Pi 兼容的蓝牙适配器”。在继续之前,确保已将适配器插入 Pi 的一个 USB 端口。
安装并启用蓝牙
在你开始编写下一个 Python 脚本之前,你需要确保蓝牙已安装在 Pi 上,并且cwiid库已设置好。从插座为你的 Raspberry Pi 供电,然后从终端运行以下命令:
pi@raspberrypi:~ $ sudo apt-get update
然后运行以下命令:
pi@raspberrypi:~ $ sudo apt-get install bluetooth
如果你已经安装了蓝牙,你应该会看到一个对话框,显示bluetooth is already the newest version。如果没有看到此消息,请按照蓝牙安装流程进行操作。
接下来,你需要为 Python 3 下载并安装cwiid库。我们将从GitHub获取这段代码,GitHub 是一个程序员和开发者分享软件的站点。
在 Pi 的主文件夹中运行以下命令:
pi@raspberrypi:~ $ git clone https://github.com/azzra/python3-wiimote
现在,你应该已经将cwiid库的源代码下载到你的 Raspberry Pi 中,并存储在一个名为python3-wiimote的新文件夹中。在我们开始下一个 Python 程序之前,源代码需要先进行编译,这是将软件制作并准备好在设备上使用的过程。
在继续操作之前,你还需要安装其他四个软件包。输入以下命令一次性安装所有四个软件包:
pi@raspberrypi:~ $ sudo apt-get install bison flex automake libbluetooth-dev
如果提示你同意继续,请按 Y(默认选项)。该命令执行完成后,切换到新下载的目录,其中包含你的 Wiimote 源代码:
pi@raspberrypi:~ $ cd python3-wiimote
接下来,你必须通过依次输入以下每个命令来准备编译库。这些都属于编译过程的一部分——你不必担心每个命令的具体内容!前两个命令不会输出任何内容,但其余的命令会输出。我将在这里展示每个输出的开始部分:
pi@raspberrypi:~/python3-wiimote $ aclocal
pi@raspberrypi:~/python3-wiimote $ autoconf
pi@raspberrypi:~/python3-wiimote $ ./configure
正在检查 gcc... gcc
正在检查 C 编译器是否工作... 是
正在检查 C 编译器默认输出文件名... a.out
正在检查可执行文件的后缀...
--snip--
然后,最终安装 cwiid 库,输入:
pi@raspberrypi:~/python3-wiimote $ make
make -C libcwiid
make[1]: 进入目录 '/home/pi/python3-wiimote/libcwiid'
--snip-
注意
如果你在安装 Python 3 cwiid 时遇到问题,请查看本书网站,看看是否有更新的过程: nostarch.com/raspirobots/。
之后,cwiid 应该能在 Python 3 中正常工作了!现在,你可以退出 python3-wiimote 目录,回到存放其他代码的地方。
编写远程控制功能
现在创建并打开一个新的 Python 程序来存储 Wiimote 代码。我将其命名为 remote_control.py:
pi@raspberrypi:~/robot $ nano remote_control.py
一般来说,在开始编写代码之前,首先规划你到底想做什么是很重要的。在我们的例子中,我们需要考虑如何让 Wiimote 精确地控制机器人。让我们做个计划。
Wiimote 有 11 个数字按钮,这对于这个简单的项目来说已经足够了。有趣的是,其中 4 个按钮属于 D-pad——Wiimote 顶部的四向控制按钮,见 图 4-5。

图 4-5 Wiimote 的四向 D-pad
这正好符合我们的需求:我们可以用上方向键让机器人向前进,用右方向键让机器人向右走,用下方向键让机器人向后退,用左方向键让机器人向左走。这和我们之前写的程序非常相似,只不过现在我们从 Wiimote 获取输入,而不是预先编写好。
我们还需要一些东西来让机器人停止。Wiimote 底部的“B”触发按钮非常适合这个功能。让我们在 Nano 中写一些代码来执行我们所做的计划;见 Listing 4-2。我将这个程序保存为 remote_control.py。
import gpiozero
import cwiid
➊ robot = gpiozero.Robot(left=(17,18), right=(27,22))
print("Press and hold the 1+2 buttons on your Wiimote simultaneously")
➋ wii = cwiid.Wiimote()
print("Connection established")
➌ wii.rpt_mode = cwiid.RPT_BTN
while True:
➍ buttons = wii.state["buttons"]
➎ if (buttons & cwiid.BTN_LEFT):
robot.left()
if (buttons & cwiid.BTN_RIGHT):
robot.right()
if (buttons & cwiid.BTN_UP):
robot.forward()
if (buttons & cwiid.BTN_DOWN):
robot.backward()
if (buttons & cwiid.BTN_B):
robot.stop()
清单 4-2 编程让你的机器人响应 Wiimote 的 D-pad
如前所述,你首先需要导入 gpiozero 和新的 cwiid 库。接着,创建一个 Robot 对象 ➊。
在接下来的代码部分 ➋,你会设置 Wiimote。与Robot对象类似,我们将Wiimote对象赋值给一个名为wii的变量。当这行代码执行时,Raspberry Pi 和 Wiimote 之间会进行配对握手。用户需要同时按住Wiimote 上的 1 和 2 按钮,将 Wiimote 设置为蓝牙可发现模式。我们在这里添加了一个print()语句,提醒用户何时按下按钮。
如果配对成功,代码会打印出一条正面的消息给用户。接着,我们开启 Wiimote 的报告模式 ➌,这样 Python 就可以读取不同按钮和功能的值。
之后,我们使用一个无限while循环来告诉机器人当每个按钮被按下时该做什么。首先,循环会读取 Wiimote 的当前状态 ➍,即检查哪些按钮被按下。这些信息会被存储在一个名为buttons的变量中。
最后,我们开始程序的最后一部分 ➎:一系列if语句和条件,用来为每个按钮分配一个动作。举个例子,第一个if语句确保当按下 D-pad 的左按钮时,机器人会向左转。接下来的代码行应用了类似的逻辑:如果按下 D-pad 的右按钮,机器人会向右转,依此类推。
像往常一样,一旦你完成编写程序,退出 Nano 并保存你的工作。
运行你的程序:远程控制你的机器人
把你的机器人放在一个大的平面上,并准备好 Wiimote。如果你的 Pi 需要蓝牙适配器,不要忘记将其插入 USB 端口。要运行程序,可以使用 SSH 终端输入以下命令:
pi@raspberrypi:~/robot $ python3 remote_control.py
程序执行后不久,终端会弹出一个提示,要求你同时按住 Wiimote 上的 1 和 2 按钮。你需要一直按住这两个按钮,直到收到成功消息,最多可能需要 10 秒钟。蓝牙配对过程可能会有点儿挑剔,所以尽量在程序提示时尽早按下这两个按钮。
如果配对成功,另一个消息Connection established会出现。否则,如果配对失败,则会显示错误消息No Wiimotes were found,并且程序会崩溃。如果发生这种情况,且你使用的是官方任天堂品牌的 Wiimote,那么很可能是你按下 1 和 2 按钮的速度不够快!重新运行程序并尝试再次进行配对。
现在 Wiimote 已经成功连接,你应该能够通过按下按钮让你的机器人朝任何你想要的方向快速移动!记得你可以随时通过按下 Wiimote 底部的 B 按钮来停止两个电机。像往常一样,你可以通过按 CTRL-C 来终止程序。
改变电机速度
到目前为止,你的机器人只能以两种速度行驶:0 英里每小时或最快速度!你可能已经注意到,这并不是最方便的。以全速行驶使得精确操控几乎不可能,你可能已经撞到了一些东西。幸运的是,情况不必总是如此。让我们给你的机器人增加一些速度控制。
在这个项目中,我们将在之前的示例基础上,创建一个具有可变电机速度的遥控机器人。为此,我将介绍一种叫做脉宽调制(PWM)的技术,并解释如何在 Python 的 GPIO Zero 库中使用它。我们还将利用一种特殊的传感器,叫做加速度计,在 Wiimote 中进行充分利用,创造出一个大大改进的遥控程序版本!
理解 PWM 是如何工作的
树莓派能够提供数字输出,而不能提供模拟输出。数字信号只能是开或关,介于两者之间没有状态。相比之下,模拟输出可以设置为零电压、满电压或任何介于两者之间的电压。在树莓派上,任何时刻 GPIO 引脚的状态要么是开,要么是关,即无电压或满电压。按照这个逻辑,连接到 Pi 的电机只能停止或全速运转。
这意味着,例如,无法将 Pi 的 GPIO 引脚设置为“半电压”来实现电机速度的一半。幸运的是,PWM 技术使我们能够近似地实现这一行为。
为了理解 PWM,首先请查看图 4-6 中的图表。它描绘了数字输出从低电平到高电平的变化。这就是当你打开树莓派的 GPIO 引脚时发生的情况:它从 0 V 变为 3.3 V。

图 4-6 从低电平(0 V)到高电平(3.3 V)的状态变化
PWM 通过快速地打开和关闭一个 GPIO 引脚,使得设备(在我们这个例子中是电机)仅“注意到”任何给定时刻的平均电压。这意味着电压的状态介于 0 V 和 3.3 V 之间。这个平均电压取决于占空比,即信号在给定周期内“开”与“关”的时间比例。它以百分比表示:25%意味着信号在 25%的时间内为高电平,75%的时间内为低电平;50%意味着信号在 50%的时间内为高电平,另 50%为低电平,依此类推。
占空比按比例影响输出电压,如图 4-7 所示。例如,对于树莓派,在 50%占空比下进行脉宽调制会给出 50%的电压:3.3 V / 2 = 1.65 V。

图 4-7 两种不同的 PWM 电压波形:25%占空比(上)和 50%占空比(下)
尽管 PWM 不是模拟信号的完美近似,但在大多数情况下,它表现良好,尤其是在这一层次上。通过数字编码模拟信号的电平,你将能够精确控制机器人运动的速度。
GPIO Zero Python 库的作者使得使用 PWM 调节电机速度变得非常简单,因此你无需了解其背后的具体机制。你需要做的就是在每个电机指令的括号中提供一个介于 0 和 1 之间的值,表示从 0% 到 100% 的值,如下所示:
robot.forward(0.25)
time.sleep(1)
robot.left(0.5)
time.sleep(1)
robot.backward()
time.sleep(1)
注意
如果你的机器人在前面的例子中运行得太快,随时可以返回并使用这种方法调整前两个项目中的速度!
该程序将命令你的机器人以其最大速度的 25% 向前移动 1 秒,然后以最大速度的 50% 向左转动 1 秒,再以全速倒退 1 秒。如果你没有提供数值,Python 将假定机器人应该以全速移动,就像你输入 1 一样。
理解加速度计
在我们改进前一个项目中的遥控程序之前,让我们先了解一下 Wiimote 中的加速度计以及我们如何使用它。
之前,你使用了 Wiimote 的方向键来进行控制。这四个按钮是数字按钮,只能检测是否被按下或松开。这对于同时控制速度和方向并不理想。
然而,在每个 Wiimote 内部,都有一个叫做加速度计的传感器,它能够检测并测量 Wiimote 在任何时刻所经历的加速度。这意味着,移动 Wiimote 在空中时,提供了三个轴上的感应数据:x、y 和 z。通过这种方式,加速度计可以跟踪运动的方向和该方向的速度。参见 图 4-8 以查看示意图。

图 4-8 Wiimote 加速度计可以检测的运动轴
这种模拟数据非常适合用于变速电机遥控程序。例如,你越是将 Wiimote 向 x 方向倾斜,机器人就越快地向前移动。
查看数据
在我们重新编写机器人的程序之前,查看 Wiimote 的加速度计输出的原始数据将非常有帮助。一旦我们了解了这些输出数据的样子,就可以考虑如何操控这些数据,使其与机器人的运动相对应。
从墙壁插座为机器人上的 Pi 供电,在 Nano 中打开一个新文件并命名为 accel_test.py,然后输入 清单 4-3 中的代码——此脚本也使用了 cwiid 库,因此如果你还没有安装它,请参阅“安装并启用蓝牙”中的说明,见 第 88 页。
import cwiid
import time
➊ print("Press and hold the 1+2 buttons on your Wiimote simultaneously")
wii = cwiid.Wiimote()
print("Connection established")
➋ wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC
while True:
➌ print(wii.state['acc'])
time.sleep(0.01)
清单 4-3 打印原始加速度计数据的代码
这个简单的程序每 0.01 秒将 Wiimote 的加速度计数据打印到终端。
print()语句表示 Wiimote 设置的开始 ➊。接下来的三行与之前的项目相同,唯一的区别是代码块的最后一行 ➋,这行代码不仅开启了 Wiimote 的报告模式,还允许 Python 读取按钮和加速度计的值。如果你以前没见过,这行中的键盘字符被称为竖线或管道符。它通常与反斜杠在同一个键上。
一个无限while循环打印加速度计的状态 ➌。下一行代码会在每次while循环迭代之间等待 0.01 秒,使得输出数据更易管理。在编程中,每次循环执行一次就称为一次迭代。
你可以通过以下命令运行此程序:
pi@raspberrypi:~/robot $ python3 accel_test.py
配对 Wiimote 后,加速度计数据应该开始打印到终端。以下是我在终端中看到的一些输出数据:
(147, 123, 136)
(151, 116, 136)
(130, 113, 140)
(130, 113, 140)
(130, 113, 140)
每一行数据作为三个值以括号形式传递,分别代表 x、y 和 z 轴,这些值会随着你在不同轴上移动 Wiimote 而变化。试着进行不同的运动,观察这些数值的变化。按 CTRL-C 退出程序。
有了这些原始数据,我们可以开始思考下一部分编程过程,即回答这个问题:你如何将这三个数据转换为机器人指令?最好的方法是通过逻辑思考并分步骤解决问题。
弄清楚远程运动控制
首先,考虑你双轮机器人的运动。因为它只在地面上移动,不会上下飞行,所以它的运动可以用两个维度来表示:x 和 y,如图 4-9 所示。我们可以忽略 z 轴数据,这样就大大简化了问题。

图 4-9 你的双轮机器人只需要两个控制轴。
其次,考虑你希望在控制机器人时如何握住 Wiimote。我决定将其水平握持,1 和 2 号按钮靠近我的右手,如图 4-10 所示。这是传统基于 Wii 的赛车游戏最常见的握持方式,也是控制机器人时的理想选择。

图 4-10 本项目中如何握持 Wiimote
当你以这种方式握住 Wiimote 时,向前和向后倾斜控制x值。左右倾斜控制y值。
当你打印加速度计数据时,你可能会注意到输出的数字通常在 95 到 145 之间。你可以再次运行测试程序来观察这一点。之所以如此,是因为最低的 x 值为 95,当 Wiimote 完全向后倾斜时;最高的值为 145,当它完全向前倾斜时。
对于 y 轴,从左到右,最低值是 95,最高值是 145。145 和 95 之间的差值是 50,这为我们提供了每个轴的可用数据范围。参见 Figure 4-11,该图说明了 Wiimote 的值是如何变化的。
到目前为止,在本章中,你通过指示机器人以全速向前、向后、向左或向右移动来控制其运动。我们希望改变这一点,根据加速度计的值来调整速度。幸运的是,GPIO Zero Python 库中的 Robot 类有另一种打开电机并设置其速度的方法,正好符合我们的需求。

FIGURE 4-11 Wiimote 的极端加速度计值
Robot 类有一个 属性——一个类中的变量——叫做 value。在任何给定时刻,value 表示机器人电机的运动,是一对介于 -1 和 1 之间的数值。这对数值中的第一个值表示左电机的速度,第二个值表示右电机的速度。例如,(–1, –1) 表示全速向后,(0.5, 0.5) 表示半速向前。值为 (1, –1) 表示全速向右转。通过设置 value 属性,你可以将机器人操控至任何你希望的方向。这将在即将到来的程序中大有用处!
编程使你的机器人实现变速
现在我们已经拆解了这个问题,并找到了一个简洁高效的最终方法来编写程序,我们可以开始编码了!使用 Nano 创建一个名为 remote_control_accel.py 的新程序,并输入 Listing 4-4 中显示的代码。
import gpiozero
import cwiid
robot = gpiozero.Robot(left=(17,18), right=(27,22))
print("Press and hold the 1+2 buttons on your Wiimote simultaneously")
wii = cwiid.Wiimote()
print("Connection established")
wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC
while True:
➊ x = (wii.state["acc"][cwiid.X] - 95) – 25
y = (wii.state["acc"][cwiid.Y] - 95) – 25
➋ if x < -25:
x = -25
if y < -25:
y = -25
if x > 25:
x = 25
if y > 25:
y = 25
➌ forward_value = (float(x)/50)*2
turn_value = (float(y)/50)*2
➍ if (turn_value < 0.3) and (turn_value > -0.3):
robot.value = (forward_value, forward_value)
else:
robot.value = (-turn_value, turn_value)
LISTING 4-4 编程让你的机器人响应 Wiimote 的运动
注意
Python(以及许多其他编程语言)可以以不同的方式处理数字。Python 中的主要两种数字类型是 整数 和 浮点数。* 整数是没有小数点的整数。浮点数(浮动点实数)有小数点,能够表示数字的整数部分和小数部分。例如,8 是一个整数,而 8.12383 或 8.0 是浮点数。在* remote_control_accel.py 程序中,我们需要使用浮点数,因为机器人运动将由两个介于 -1 和 1 之间的数字控制。
该程序与加速度计测试程序共享相同的 Wiimote 设置过程。然后,我们设置了一个while循环以保持代码的运行。第一个语句 ➊ 从加速度计读取x值,并将其存储在一个名为x的变量中。在该变量中,值经过两次算术操作。首先,减去 95;这将数据限制在 0 到 50 之间,而不是在 95 到 145 之间,从而使其适应我们之前发现的可用范围。其次,再减去 25。这确保了数据的范围将在-25 到+25 之间。然后对y值进行完全相同的处理,结果存储在一个名为y的变量中。
我们需要这样做,因为Robot类的value属性接受负值表示后退运动,正值表示前进运动。这个操作平衡了加速度计数据的正负值,使得哪一边是后退,哪一边是前进变得清晰。
四个if语句 ➋ 消除了程序后续错误的可能性。在不太可能的情况下,如果 Wiimote 的加速度计输出的数据不在-25 到+25 的范围内,if语句会捕捉到这个情况,并将其四舍五入到相关的极限值。
接下来,确定机器人的最终 x 轴值并将其存储在一个名为forward_value的变量中 ➌。这个计算将x变量的值除以 50,得到一个介于-0.5 和 0.5 之间的新比例值。然后将这个结果乘以 2,以获得一个介于-1 和 1 之间的值。相同的过程会重复进行,以得到最终的 y 轴值,并将其存储在一个类似的变量turn_value中。
第➍行开始了一个if/else条件语句。如果turn_value小于 0.3 或大于-0.3,则robot.value被设置为forward_value。因此,如果 Wiimote 倾斜不到 30 度,程序会假设你希望机器人前进或后退。这意味着 Wiimote 稍微倾斜时,机器人不会误转向。然后,机器人的前进/后退速度将根据 Wiimote 的俯仰角度来设置。例如,如果 Wiimote 完全向前倾斜,它将把robot.value设置为(1, 1),你的机器人将加速向前移动。
另外,如果 Wiimote 倾斜超过 30 度,程序会假设你希望机器人在原地向左或向右转动。程序随后根据 Wiimote 的倾斜角度来旋转机器人。例如,如果 Wiimote 完全倾斜到右边,机器人会非常快速地向右旋转;但如果 Wiimote 只是稍微倾斜到右边,机器人则会较慢且更加平稳地转动。
和往常一样,完成程序后,退出 Nano 并保存工作。
运行你的程序:通过 PWM 远程控制你的机器人
断开你的机器人与墙壁插座的连接,确保它由电池供电。然后将它放置在一个大表面上,手持你的 Wiimote 并保持水平方向。要运行你的程序,请输入:
pi@raspberrypi:~/robot $ python3 remote_control_accel.py
在完成熟悉的蓝牙握手过程后,你的机器人应该开始运行,并随着你改变 Wiimote 的方向而移动。试着用不同的速度驾驶它,并练习操作!
挑战自己:完善你的遥控机器人
当你对遥控机器人的行为有了一定的了解后,重新查看代码并根据需要进行改进。例如,你可以尝试使转向更灵敏、限制机器人的速度,甚至让机器人在按下按钮时按照预定义的模式移动。可能性是无穷无尽的!
概述
本章带领你将一个机器人形状的纸重物变成一个完全功能的 Wiimote 遥控小机器!我们涵盖了从 H 桥到 PWM 再到加速度计的广泛概念。在这个过程中,你写了三个程序,每个比上一个更高级。
在下一章,我将指导你如何使你的机器人变得更智能,使它能够自动避开障碍物!
第五章:避免障碍物
现在你可以控制你的机器人如何移动,这已经很酷了!但如果让你的机器人自行控制自己,不是更酷吗?
你可能已经注意到,你的小两轮在地板上跑时容易受到各种危害的影响。撞到墙壁和其他物体不仅令人烦恼,甚至可能对硬件造成危险。在本章中,我将向你展示如何让你的机器人能够自主地检测并避开障碍物。我们将讲解障碍物检测的原理以及如何使用你所需要的传感器。
障碍物检测
为了让你的机器人能够避开障碍物,它首先需要能够感知这些障碍物。在电子学中,我们使用专门的传感器来完成这个任务。使用传感器实现障碍物检测有多种方法。在业余爱好者层面,有两种主要方法:数字检测和模拟检测。数字检测非常擅长在特定范围内感知障碍物,但无法确定与障碍物之间的距离。而模拟检测则能同时做到这两点,这也是我们在这里使用的方法,以使我们的机器人更加智能。
使用超声波传感器进行模拟物体检测
HC-SR04 超声波传感器(如图 5-1 所示)利用超声波来测量传感器与物体之间的距离。该传感器的工作原理与自然界中的蝙蝠和海豚声纳以及非自然界中的潜艇声纳相似。

图 5-1 HC-SR04 超声波距离传感器
声音可以被建模为波动,具有不同的波长。人耳只能听到声音频谱中的一小部分范围。任何频率高于此范围(20 kHz+)的声音波都是超声波。超声波距离传感器的设计目的是通过超声波反射来感知物体的接近。这种声纳系统发出波,波遇到障碍物后反弹。接收器随后探测回来的声波。超声波在短距离内(大约几米)非常准确,并且人类无法听到。
理解 HC-SR04 的工作原理
像 HC-SR04 这样的基本超声波距离传感器由发射器、接收器和一些电路组成。发射器和接收器是像眼睛一样的扬声器状突起,见图 5-1。
为了确定距离,发射器发出高频超声波声音。这种声音会反弹并反射到任何附近的固体物体上。反弹的信号会被 HC-SR04 上的接收器探测并接收。
声音在空气中以恒定的速度传播。在室温下(20º C/68 ºF),声音波的传播速度大约为 343 米/秒(m/s)。虽然这个速度很快,但并非瞬时的,这意味着声音发出和反弹接收到之间存在一个小的时间差。因此,我们可以通过计时信号从传感器发出到返回所需的时间来测量距离。
速度、距离和时间之间的关系可以总结如下:

一个物体的速度(以米/秒为单位)等于该物体在米中行进的距离除以它所花费的时间(以秒为单位)。我们将使用这个公式来计算距离。我们知道声音的传播速度是恒定的,为 343 m/s,而且我们可以测量声音波反射回来的时间,也就是所用时间。如果你调整公式来解距离,你就会得到:

然而,这并不是全部。超声波脉冲被发出,碰到物体后反射回来,并被 HC-SR04 接收,如图 5-2 所示,这意味着声音波实际上是从传感器到物体的距离双倍传播。

图 5-2 HC-SR04 距离测量过程
这意味着我们需要将超声波距离传感器记录的时间除以二,从而得到以下公式:

我们已经有了方法,现在让我们来试试。
测量短距离
现在你已经理解了超声波距离测量背后的数学和原理,是时候将一切付诸实践,测量一些距离了!
配件清单
除了你在树莓派机器人上已经拥有的面包板,你还需要以下组件:
-
一个 HC-SR04 超声波传感器
-
一个 1 kΩ 电阻
-
一个 2 kΩ 电阻
-
跳线
价格便宜的 HC-SR04 传感器在常见的在线零售商处广泛销售。只需搜索“HC-SR04”,你应该不用花超过几美元就能买到一个。
任何数字系统都有两种逻辑状态:低电压(0)和高电压(1)。这在第四章解释 PWM 时首次引入。通常,低电压就是地线,0 V;然而,高电压可能会因系统而异。这意味着一些系统需要 5 V 信号才能触发高电压,而其他系统可能只需要 3.3 V。例如,这正是我们所面临的情况!HC-SR04 需要 5 V,而你的树莓派使用 3.3 V 逻辑。请注意,在图 5-3 中,超声波传感器上有四个引脚:Vcc 为电源,Trig 为触发脉冲,Echo 为回声脉冲,最后是 Gnd 为地。

图 5-3 HC-SR04 模块引脚的特写
你需要使用 5V 电源为模块供电,接到 Vcc 引脚。当 HC-SR04 接收到反射回来的脉冲时,Echo 引脚会设为 5V 高电平。但如果我们将这个直接连接到树莓派上,高电压会造成严重损坏。为避免这种情况,你需要将传感器的输出电压降低到树莓派能够承受的范围——这就是 1 kΩ和 2 kΩ电阻派上用场的地方。我们将用它们来搭建一个电压分压器。
使用电压分压器降低电压
电压分压器 是一种简单的电路,它将较大的电压转换为较小的电压。电压分压器接受输入电压,使用两个串联的电阻来降低并输出电压。你可以选择不同值的电阻,使输出电压成为输入电压的某一比例。
电压分压电路如图 5-4 所示。注意,输出电压是从两个电阻之间取出的。

图 5-4 电压分压电路
和大多数电子设备一样,我们使用一个方程来将两个电阻(R[1] 和 R[2])与输入和输出电压(V[in] 和 V[out])数学关联起来。物理学家言简意赅,所以这个方程被直接称为 电压分压方程:

使用这个公式,你可以计算出所需的 R[1] 和 R[2] 电阻值,以产生所需的输出电压。R[1] 和 R[2] 的具体数值其实并不重要,重要的是它们之间的比例。例如,如果 R[1] 和 R[2] 相等,那么输出电压将是输入电压的一半。
警告
无论你最后得到什么电阻值,最好使输出电压低于目标电压,而不是高于目标电压。这是因为较低的电压不会损坏你的树莓派或其他电子设备,而稍微高一点的电压就可能会造成损坏。
让我们用这个公式来计算我们机器人距离传感器所需的电阻值。已知输入电压为 5V,所需的输出电压为 3.3V,因此方程中有两个未知数:R[1] 和 R[2]。你可以选择一个常见的电阻值来确定其中一个,剩下的就只有一个未知数,这样就更容易计算了。我们选择 1 kΩ作为 R[1]。通过重新排列方程并解出 R[2],你会得到:

如果你代入已知的数值,R[2] 会按如下方式计算:

找到一个精确值为 1941.176471 Ω 的电阻器将非常困难!所以我们将选择最接近的常见电阻值。在我们的情况下,2 kΩ 或 2.2 kΩ 电阻就足够了。如果有疑问,尝试找到一个接近但稍微低于所需值的电阻器。如果需要,你可以将这两个电阻值重新代入方程式,计算出该电阻组合的输出电压,以便进行二次检查。
接线你的 HC-SR04
现在你已经拥有了所有必要的组件,可以开始接线你的距离传感器了。和往常一样,在开始操作接线和连接新组件之前,确保你的 Pi 和机器人电源已经断开。
我们不会直接将 HC-SR04 模块插入面包板,而是通过长跳线连接,这样你可以将距离传感器放置在机器人上的任何位置。使用上一章中已经接好电机的构建,按照这些说明进行操作,但暂时不要将传感器安装到机器人底盘上:
-
使用一根长跳线将 HC-SR04 的 Vcc 引脚连接到你的面包板上的 Pi +5 V 电源轨。
-
使用另一根长跳线将 HC-SR04 的 Gnd 引脚连接到面包板上的接地轨。此时你的接线应该像 图 5-5 所示。
![image]()
图 5-5 HC-SR04 模块连接到 +5 V 和接地。电机控制芯片和电机在图中省略,但你应该将它们保持连接到电路中。橙色条纹表示 L293D 芯片及其接线所占的区域。
-
接下来,使用一根线将 HC-SR04 的 Trig 引脚直接连接到 Raspberry Pi 的物理引脚 16。Pi 的引脚 16 也被称为 BCM 23。
-
然后,将跳线从传感器的 Echo 引脚连接到面包板上的新行。在同一行中插入一个 1 kΩ 电阻器,一端插入 Echo 引脚所在的行,另一端插入面包板上另一个未使用的行。此时你的接线应该像 图 5-6 所示。
![image]()
图 5-6 HC-SR04 的 Trig 引脚连接到 BCM 23,Echo 引脚连接到 1 kΩ 电阻器
-
将 Raspberry Pi 的物理引脚 18(BCM 24)接到你刚刚连接的 1 kΩ 电阻器另一端的行。
-
最后,将 2 kΩ/2.2 kΩ 电阻的一端插入与 1 kΩ 电阻和跳线相连的行,另一端连接到 Pi 的 BCM 24 引脚,并将此电阻的另一端接到接地轨。面包板上的完整电路应该像 图 5-7 所示。
图 5-8 显示了最终结果的电路图。

图 5-7 完整的面包板电路图,其中包含了 HC-SR04 和电压分压器

图 5-8 HC-SR04 连接到 Raspberry Pi 的电路图
编程你的树莓派读取距离
现在你的超声波距离传感器已经接好电路,是时候深入一些 Python 代码来使用这个传感器了。从墙壁插座启动你的树莓派,登录后,找到保存程序的robot文件夹。使用以下命令创建一个名为distance_test.py的新程序:
pi@raspberrypi:~/robot $ nano distance_test.py
在这个项目中,我们仍然使用 GPIO Zero Python 库,但我们将远离内置函数和对象。相反,我将向你展示如何从头开始编程和操作 HC-SR04!
Listing 5-1 中的代码将发送出一个信号,也就是所谓的ping,然后读取并打印出信号遇到的第一个物体的距离。将这段代码保存到你已打开的distance_test.py文件中。尝试用你的编程技能阅读并解读它,然后再继续我的解释!
import gpiozero
import time
➊ TRIG = 23
ECHO = 24
➋ trigger = gpiozero.OutputDevice(TRIG)
echo = gpiozero.DigitalInputDevice(ECHO)
➌ trigger.on()
time.sleep(0.00001)
trigger.off()
➍ while echo.is_active == False:
pulse_start = time.time()
➎ while echo.is_active == True:
pulse_end = time.time()
➏ pulse_duration = pulse_end - pulse_start
➐ distance = 34300 * (pulse_duration/2)
round_distance = round(distance,1)
print("Distance: ", round_distance)
LISTING 5-1 用于测量单一距离的程序
通常,我们首先导入gpiozero和time库,以便在代码中使用。
在➊和接下来的行中,我们创建了两个变量,TRIG和ECHO,它们分别存储连接到 Trig 和 Echo 引脚的引脚编号。我们将这些变量大写,以表示它们是常量——我们希望在程序运行期间保持不变的变量。
大写常量是编程约定,告诉你和任何阅读代码的人,这些值在程序执行过程中不会改变。值得强调的是,虽然这是一种约定,但它仅仅是大多数程序员的做法,而不是 Python 强制要求的。即使这些常量使用小写字母,或者大小写混合,代码仍然能正常工作。
以下两行 ➋ 设置了连接到 HC-SR04 的 Trig 和 Echo 引脚的 GPIO 引脚。我们将trigger变量设置为输出,因为它发送 ping 信号,而将echo设置为输入,因为它接收 ping 信号。
为了触发 ping 信号,HC-SR04 传感器需要一个快速的 10 µs 脉冲(1 µs 是百万分之一秒:0.000001 秒),这个脉冲将在接下来的代码段 ➌ 中执行。
当发射器发送出 ping 信号时,程序必须等待 ping 信号清除接收器,然后才开始监听回声。这是因为 HC-SR04 的发射器和接收器非常接近,因此在发射后的一段微秒时间内,传感器可能会听到发出的脉冲。我们不希望不小心记录下发射脉冲,因此我们告诉程序,直到它听到回声,而不是原始的 ping 信号时,才开始接收。这就像是你和朋友站在一个大房间里,你们想听回声。如果你大声喊“你好!”,你的朋友会在你听到回声之前就听到你的声音。这种效应是我们在使用 HC-SR04 时必须避免的。
代码的下一部分负责确保我们能够接收到回声。while 循环➍,其条件是 echo.is_active == False,会一直重复,直到传出的脉冲不再被传感器接收到。程序随后将脉冲清除接收器的准确时间存储在一个名为 pulse_start 的新变量中。
由于传出的脉冲已经被移除,while 循环,条件是 echo.is_active == True ➎,会在回声返回到传感器时捕获它。此时创建了第二个变量 pulse_end,用于记录回声脉冲的准确时间。
然后,我们只需从接收到信号的时间中减去发送信号的时间,就能计算出回声返回所花费的时间。我们将结果存储在名为 pulse_duration ➏ 的变量中。
可以说,这个程序最重要的部分是 ➐,我们根据回声返回所花费的时间来计算距离。我们将之前的公式应用到程序中收集到的数值:

我们没有使用 343 m/s 这个声速值,而是将其乘以 100,以便得到一个以厘米为单位的距离值,这对于你的机器人处理的距离更为相关。
最后,在程序的最后几行,我们将距离值四舍五入到小数点后一位,然后将其输出到终端。
运行你的程序:测量短距离
现在你已经完成了代码,是时候测试超声波距离传感器及其准确性了。
将你的 HC-SR04 平行放置在一个表面上,比如桌子。然后在传感器前面放置一个相对较小的固体物体,并用直尺测量距离。在 图 5-9 中,我使用的是一个竖直的盒子。我的盒子大约距离 HC-SR04 20 厘米。

图 5-9 我的 HC-SR04 测试设置
如常,要运行你的程序,请输入:
pi@raspberrypi:~/robot $ python3 distance_test.py
一段时间后,应该会在终端显示单个距离读数,程序将结束。对我来说,输出结果如下所示:
pi@raspberrypi:~/robot $ python3 button.py
距离:20.1
你的 HC-SR04 应该已经成功测量了它与物体之间的距离!我的测量结果相当准确,但你不应该期望这些读数的准确性达到百分之百。
如果你的读数偏差较大,尝试重新运行程序,看看该输出是否只是一个异常值。如果你仍然得到错误的读数,检查程序中的数字和公式:数值是否正确,数学是否应用正确?如果程序停滞不前(无反应)且永远不会完成执行,检查你的电线是否连接正确,并参考章节前面的说明。如果程序没有接收到回声,它也可能会停滞不前。这可能是因为你试图测量的距离超出了范围。然而,室内使用时应该不会出现问题。
最后,如果你仍然遇到问题,可以查阅代码,确保它与你在清单 5-1 中的程序完全相同。像往常一样,你可以从https://nostarch.com/raspirobots/获取确切的代码示例。
让你的机器人避开障碍物
现在你已经掌握了使用超声波传感器测量单个距离的技巧,你可以将传感器安装到你的机器人上,并编写一个新程序,使用 HC-SR04 来避开障碍物。
到这个项目结束时,你将拥有一个完全自主的避障机器人!目标是确保你的树莓派机器人在采取回避动作之前,离任何物体的距离不小于 15 厘米。
安装你的 HC-SR04 超声波传感器
安装距离传感器的最佳位置是机器人前方,尽量选择一个尽可能居中的位置。我推荐使用粘性胶粘物或双面胶带固定传感器。该模块只能在直接的直线范围内感知距离,因此不要将其安装得离地面太高,否则你的机器人很可能会撞到低矮的障碍物。
我将我的 HC-SR04 安装在前方稳定器上,如图 5-10 所示。传感器离地面大约一厘米。请注意,传感器的方向也无关紧要:我的安装方式是倒过来的!

图 5-10 我将 HC-SR04 安装在我的机器人前方
编写程序使你的机器人避开障碍物
为了创建避障程序,我们将大量借用前一节的代码,但将距离传感器设置为持续扫描即将到来的障碍物。
在清单 5-1 中,我们编写了 10 行代码来测量单个距离。在接下来的程序中,我们需要持续重复这段代码,以便不断刷新机器人与任何即将到来的障碍物之间的距离。我们可以每次需要时都写出这段代码,但那样既费时又单调,而且我们也不知道需要写多少次。相反,有一种方法可以将代码打包,这样你就可以在任何需要时随时使用它。像这样打包代码创造了所谓的函数。
Python 函数是一个组织好的、可重用的代码块,它执行某个操作。让我们来试试:输入清单 5-2 中的避障程序代码,并将其保存为obstacle_avoider.py文件在你的树莓派上。
import gpiozero
import time
➊ TRIG = 23
ECHO = 24
trigger = gpiozero.OutputDevice(TRIG)
echo = gpiozero.DigitalInputDevice(ECHO)
➋ robot = gpiozero.Robot(left=(17,18), right=(27,22))
➌ def get_distance(trigger, echo):
➍ trigger.on()
time.sleep(0.00001)
trigger.off()
while echo.is_active == False:
pulse_start = time.time()
while echo.is_active == True:
pulse_end = time.time()
pulse_duration = pulse_end - pulse_start
distance = 34300 * (pulse_duration/2)
round_distance = round(distance,1)
➎ return(round_distance)
while True:
➏ dist = get_distance(trigger,echo)
➐ if dist <= 15:
robot.right(0.3)
time.sleep(0.25)
➑ else:
robot.forward(0.3)
time.sleep(0.1)
清单 5-2 避障程序
该程序首先导入必要的库。然后,你像在清单 5-1 中那样设置 HC-SR04 的 Trig 和 Echo 引脚,标记➊并设置➋。这也初始化了机器人以供使用。
在第➌步,你将遇到第一个 Python 函数,它以代码块的形式组织。要开始一个函数块,你使用关键词def。这是define的缩写,因为你在定义代码块应该执行的功能。
在def之后,输入函数的名称,像变量一样,它可以是任何名字(前提是不能以数字开头)。最好保持函数名称简短、直观。这个函数的目的是触发传感器并返回距离测量,因此我将这个函数命名为get_distance()。
函数名称后面跟着括号,括号中的内容被称为函数的参数或实参。这些参数允许我们将信息传递给函数以供后续使用。在我们的例子中,我们传递了之前设置的触发器和回声引脚信息,这样函数就能够激活并使用 HC-SR04 距离传感器。
与while和for循环一样,你需要对函数内部的代码进行缩进,这样 Python 就知道哪些代码属于该函数。缩进代码从➍开始,到➎结束,并且它与清单 5-1 中用于获取距离读取的代码完全相同。
在➎部分,代码返回函数的最终输出:距离读取。返回信息意味着每次调用该函数时,函数的输出都会传递回程序。然后这些输出可以打印到终端,赋值给变量,或以你作为编程者希望的任何方式进行处理!
然后我们启动一个无限while循环。首先我们调用get_distance()函数,并将结果存储在变量dist中➏。
接下来,我们通过一个条件if语句➐引入了关键的避障逻辑。这行代码的意思是:“如果传感器与障碍物之间的距离小于 15 厘米,执行以下操作。”如果条件成立,语句中的两行代码会执行,使机器人慢慢向右转动,持续四分之一秒。
最后,代码中的➑部分处理任何其他情况。如果障碍物距离传感器超过 15 厘米,机器人会继续慢慢前进,持续十分之一秒。避障程序通常在机器人以较慢速度行驶时效果更好,因此我们在此通过(0.3)参数将机器人的速度设为其最大速度的 30%。如果你发现这个速度对你构建的机器人来说太慢或太快,可以随意增加或减少电机命令中的括号内的值。
运行你的程序:让你的机器人避开障碍物
现在最后一段代码已经完成,建议你清理出一个足够大的区域,然后根据你的超声波距离传感器的正确高度有策略地放置障碍物。可以参考我为我的机器人快速创建的图 5-11。

图 5-11 我的机器人正面对一些竖立的文件夹
使用以下命令运行你的程序:
pi@raspberrypi:~/robot $ python3 obstacle_avoider.py
你的机器人应该会活跃起来,向前行驶,直到遇到第一个障碍物,这时它应该转动,直到障碍物被清除,然后继续前进。
另一个有趣的实验是站在机器人前面,看看它如何每次都能逃离你,不论你怎么移动双脚站在它前方!
一如既往,使用 CTRL-C 命令停止机器人。
挑战自我:改进避障程序
我们的避障方法仍有很大的改进空间!
如前所述,HC-SR04 只能沿单一直线检测距离,因此你的机器人可能会错过直接在它前方、但由于过低或过高而无法感知的障碍物。
只有一个距离传感器也是一个局限。你的机器人只能检测到正前方的障碍物,因此它可能会轻易地向右或向左转,撞上另一个障碍物!你使用的距离传感器越多,机器人获得的信息就越多,因此运行的代码也能变得更智能。
尝试调整清单 5-2 中的程序,以使你的机器人尽可能高效地使用一个传感器避开障碍物。你可以编辑在采取回避动作之前的最小距离(默认是 15 cm)。或者,你可以编辑每次回避时电机开启的时间,或者调整转向的方向。尝试不同的变量值,并找出最适合的配置。
当你觉得自己已经尽可能地改进了程序后,你可以再拿一个超声波 HC-SR04 模块,像之前一样将它接到树莓派的更多 GPIO 引脚上,并自定义代码,利用这个新的数据源与第一个 HC-SR04 配合使用。如果你使用两个传感器,一个不错的安装位置是把它们安装在机器人的前角,而不仅仅是正对前方。
如果你依然充满冒险精神,你可以尝试使用第三个距离传感器,以便更全面地感知你的机器人所处的环境!
摘要
在本章中,我们涵盖了从超声波距离测量的原理到使用函数编程的所有内容。你已经将这些知识整合在一起,成功地将你的机器人变成了一个完全自主的避障机器。
在下一章,我将向你展示如何通过添加可编程 RGB LED 和音效使你的机器人更具特色!
第六章:使用灯光和声音进行自定义
让你的机器人在人群中脱颖而出是一件非常有趣的事情。在这一章中,我将展示如何为你的机器人添加灯光和扬声器,让它更加闪亮、响亮和激动人心。像往常一样,我们将涵盖理论、所需的零件以及如何使用它们。
将 NeoPixels 添加到你的树莓派机器人
吸引注意力的最好方式之一是让你的机器人展示一场灯光秀。通过正确的代码和接线,并借助一些明亮多彩的 LED,你可以让你的机器人在地板上跑来跑去时,呈现出令人眼花缭乱的精彩演出!
在这个项目中,你将为你的机器人安装一串超亮的多色 LED 灯。我将指导你获取组件、接线并编程不同的图案。我们将把这些新加入的功能与第四章中的 Wiimote 程序结合,这样你就可以通过按下 Wiimote 的按钮来触发不同的 LED 组合。
介绍 NeoPixels 和 RGB 颜色系统
在本书的开始部分,我介绍了 LED 并展示了如何将单色 LED 接到树莓派上,并通过一个简单的 Python 脚本使其闪烁。
那是一个很好的入门项目,但单一的 LED 几乎无法为你的机器人创造预期的震撼效果。因此,在这个项目中,我们将使用像图 6-1 所示的NeoPixels。

图 6-1 我的机器人上的 NeoPixels
NeoPixel 是开源硬件公司 Adafruit 推出的一款经济实惠、超亮的 RGB LED 灯。RGB代表红绿蓝,这是一种计算机用来表示大量颜色的混色系统。红色、绿色和蓝色的光可以以不同的比例组合,从而产生可见光谱中的任何颜色,从橙色到靛蓝再到绿色!通过设置 R、G 和 B 的强度,每种颜色的强度范围是 0 到 100%,你可以创建新的颜色。例如,纯红色表示 100% R、0% G 和 0% B,而紫色表示 50% R、0% G 和 50% B。
计算机通常不使用百分比来表示每种颜色的强度,而是使用从 0 到 255(256 个级别)的十进制数值。因此,对于红色,其组合为 255 R、0 G 和 0 B。请参见图 6-2,以了解完整的 RGB 范围,表示为色轮。

图 6-2 完整的 RGB 范围,表示为色轮
这意味着,与单色 LED 不同,每个 RGB NeoPixel 可以显示巨大的颜色范围。你可以通过将每个级别的可能性数相乘来计算准确的范围:256 × 256 × 256 = 16,777,216。那几乎是 1700 多万种不同的颜色!
那么,单个 LED 如何能代表如此多的颜色呢?如果你仔细看 图 6-3 中的 NeoPixel,你会发现它分为三个不同的区域。这是因为每个 NeoPixel 实际上由 三 个 LED 组成:分别是红色、绿色和蓝色。通过将这些颜色按不同的比例组合在一起,就可以产生 RGB 颜色,如前面所述。

图 6-3 NeoPixel 的宏观拍摄
部件清单
NeoPixel 可以单独使用或串联在一起,Adafruit 提供了大量的 NeoPixel 产品,种类和尺寸多种多样——从单个像素到由数百个 NeoPixel 组成的大型矩阵。
在这个项目中,我建议购买一个 NeoPixel Stick ——这是一种大约 2 英寸长、包含八个 NeoPixel 的 LED 排列,如 图 6-4 所示。它的小尺寸和明亮的输出使其非常适合用于你的机器人。

图 6-4 焊接好引脚的 NeoPixel Stick
如果你在美国,可以从 Adafruit 的网站上购买一个,价格不到 6 美元。如果你在其他国家或地区,只需在网上搜索 “NeoPixel Stick”,应该能找到类似价格的其他零售商。
值得注意的是,NeoPixel Stick 确实需要一定的组装工作:你需要将一组男性 引脚 焊接到电源和数据输入接点,如 图 6-5 所示。背面有两组看起来几乎相同的接点,唯一的区别是,一边是用于 Stick 的 输入,另一边是用于 Stick 的 输出。这样你就可以将一个 Stick 的输出连接到另一个 Stick 的输入,将多个 Stick 串联在一起。我们在这个项目中只会使用一个 NeoPixel Stick,但你可能会在以后尝试使用更多的 NeoPixel。
你需要单独购买一些男性引脚(价格不到 1 美元),并将它们焊接到包含 DIN(数据输入)引脚的接点上。
如果你从未焊接过,可以参考 第 204 页上的 “如何焊接” 进行指导。

图 6-5 我焊接好引脚的 NeoPixel Stick 背面(L);一个四引脚引脚排(R)
除了 NeoPixel Stick 和引脚外,你只需要一些跳线来连接 NeoPixel,并且需要一些粘性胶粘剂将它们固定在 Raspberry Pi 机器人上。
连接你的 NeoPixel Stick
一旦你完成了 NeoPixel Stick 的焊接,就可以将其连接到你的 Pi 上。总共只需要三个连接就能让它正常工作。记住,图示中我不会显示之前的连接,但你无需断开之前项目的任何连接就能继续进行这个项目。
像上一章中的 HC-SR04 一样,NeoPixel Stick 可以直接插入面包板,但和那个项目一样,我不推荐这样做。相反,最好使用跳线连接 NeoPixel Stick,这样你可以将它安装在机器人的其他地方。
-
使用跳线将 NeoPixel Stick 的 4-7VDC 引脚连接到面包板的+5V 轨道。请注意,由于这些 LED 灯非常亮,它们消耗的电流较大。因此,当我们稍后运行软件时,你需要连接并打开机器人的电池。
-
接下来,使用另一根跳线将你的 NeoPixel Stick 的一个 GND 引脚连接到面包板的公共接地轨道。这将使你的 NeoPixel 与电源(电池)和树莓派共地。查看图 6-6 了解你当前设置的示意图。
![image]()
图 6-6 Adafruit NeoPixel Stick 连接到+5V 和接地
-
使用一根跳线将你的 NeoPixel Stick 的 DIN(数据输入)引脚连接到树莓派的物理引脚 19(BCM 10)(关于引脚编号的指南请参见第 200 页的“树莓派 GPIO 图”)。完整的电路应该如下所示:图 6-7。
![image]()
图 6-7 完整的面包板示意图,显示 NeoPixel Stick 连接到电源和树莓派
使用粘性材料将你的 NeoPixel Stick 安装在机器人的某个位置。我将它安装在面包板的右侧。
安装软件
在你编程 NeoPixel Stick 之前,必须先安装和配置必要的软件。我们将使用的 Python 库叫做rpi_ws281x,你可以通过命令行工具pip从网上下载它,pip是一个快速且简便的 Python 软件安装和管理工具,适用于 Python 3。
在继续之前,你需要确保已经为 Python 3 安装了pip。为此,启动树莓派并通过 SSH 登录。然后,在终端输入以下命令:
pi@raspberrypi:~ $ sudo apt-get update
这个命令实际上并不会安装新软件,而是更新树莓派可以下载的软件列表。完成此过程后,你可以使用以下命令为 Python 3 安装pip:
pi@raspberrypi:~ $ sudo apt-get install python3-pip
很可能系统会提示你pip已为 Python 3 安装好,这样你就可以开始使用它了。如果没有安装,按照安装过程继续操作。
完成后,你可以通过一个简单的命令安装rpi_ws281x库:
pi@raspberrypi:~ $ sudo pip3 install rpi_ws281x
我们将使用 SPI 总线 来控制 NeoPixels。这只是每个 Raspberry Pi 上某些 GPIO 引脚的电子接口(确切来说是 串行外设接口)。默认情况下,SPI 是禁用的,但在开始本书时您应该已经通过图形界面启用了它。您可以通过以下命令打开 Raspberry Pi 软件配置工具,检查是否已启用 SPI:
pi@raspberrypi:~ $ sudo raspi-config
一旦工具打开,向下滚动到 Interfacing Options,选择它,然后按 ENTER。您将看到 图 6-8 中的菜单。

图 6-8 raspi-config 工具的接口选项菜单
向下滚动并选择 SPI。接下来,系统会询问您是否希望启用 SPI 接口。使用左右箭头键高亮选择 Yes。选择后,您将返回主 raspi-config 菜单。您可以通过按右箭头键两次(高亮显示 Finish)然后按 ENTER 来退出配置工具。现在使用以下命令重启您的 Raspberry Pi:
pi@raspberrypi:~ $ sudo reboot
现在 SPI 已启用!
在 PI 3 上使 SPI 正常工作
如果您使用的是 Raspberry Pi 3 Model B/B+,在继续之前,您还需要执行一个额外的步骤。如果您使用的是较旧版本的 Pi,则不需要担心此步骤。
要使 SPI 在 Pi 3 上正常工作,您需要将 GPU 核心频率更改为 250 MHz。这意味着您正在将 Raspberry Pi 3 上的图形单元设置为以稍微不同的速度运行。如果不进行此更改,您的 NeoPixels 可能会表现异常,并且无法显示正确的图案。
要进行此更改,请在终端中输入以下命令:
pi@raspberrypi:~ $ sudo nano /boot/config.txt
这将打开一个包含各种文本和选项的配置文件。向下滚动到文件底部,在新的一行添加以下文本:
core_freq=250
例如,我的配置文件的结尾是这样的:
--snip--
# Additional overlays and parameters are documented /boot/
overlays/README
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
start_x=1
gpu_mem=128
core_freq=250
添加此行后,请按 CTRL-X 保存文件,然后按 Y 和 ENTER。然后重启您的 Raspberry Pi。
注意
如果您认为此过程可能已经发生变化,或者担心自己可能做错了这一步,请访问本书网站 nostarch.com/raspirobots/。
配置库的示例代码
在继续之前,让我们测试一下您刚刚安装的库,以确保一切正常工作。如果您已经将本书附带的软件包下载到您的 Raspberry Pi 上,那么您已经拥有了测试文件 strandtest.py。该程序是由 Adafruit 编写的,用于测试 NeoPixels。如果没有这个文件,可以通过输入以下命令从互联网上下载示例代码:
pi@raspberrypi:~/robot $ wget https://raw.githubusercontent.com/
the-raspberry-pi-guy/raspirobots/master/strandtest.py
完成这些后,你将拥有与软件包中提供的完全相同的测试代码。
在运行示例代码之前,我们需要更改一些设置。要查看代码和当前设置,请使用 Nano 打开示例代码文件,如下所示:
pi@raspberrypi:~/robot $ nano strandtest.py
该程序的目的是运行多个示例灯光模式。代码相当长,充满了定义不同序列的函数,但你不需要编辑这些代码。
然而,你需要编辑程序中的一些常量。在代码的开头附近,你会找到需要编辑的代码块,示例代码见列表 6-1。
# LED strip configuration:
➊ LED_COUNT = 16 # Number of LED pixels.
➋ LED_PIN = 18 # GPIO pin connected to the pixels
(18 uses PWM!).
➌ #LED_PIN = 10 # GPIO pin connected to the pixels
(10 uses SPI /dev/spidev0.0).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually
800khz)
LED_DMA = 10 # DMA channel to use for generating
signal (try 10)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for
brightest
LED_INVERT = False # True to invert the signal (when using
NPN transistor level shift)
LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45
or 53
LED_STRIP = ws.WS2811_STRIP_GRB # Strip type and color
ordering
列表 6-1 strandtest.py 的 LED 条配置
每个井号字符(#)后的文字是注释。程序员经常在代码中添加注释作为注解。注释帮助人类读者和其他程序员理解程序的各个部分做了什么。
在 Python 中,注释以井号字符(#)开始。当 Python 解释这段代码时,它会忽略井号后的所有内容。良好的编码实践是为你的程序添加注释,特别是当你在团队中工作或开放源代码时。注释也方便作为提醒,特别是当你未来重新访问程序时,如果忘记了它是如何工作的!
你需要更改的第一件事出现在 ➊:LED_COUNT。这是一个常量,表示你连接到树莓派的 NeoPixel 数量。默认情况下,它被设置为 16,所以你需要将其更改为 8。
其次,你将更改正在使用的引脚号。常量 LED_PIN 在 ➋ 处默认设置为 BCM 18,但你的 NeoPixel Stick 连接到 BCM 10。这个示例代码的作者注意到使用 BCM 10 是一个流行的选择,所以他们在 ➌ 处提供了一个替代的常量定义,但已将其注释掉。
要交换这些行的位置,请在 ➋ 处的行首添加井号。这样会将该行注释掉,使 Python 忽略它。然后,在 ➌ 处移除井号以取消注释该行,这将使 Python 执行将 LED_PIN 赋值为 10 的代码。
你的最终常量块现在应该类似于列表 6-2 中的代码。
# LED strip configuration:
LED_COUNT = 8 # Number of LED pixels.
#LED_PIN = 18 # GPIO pin connected to the pixels (18
uses PWM!).
LED_PIN = 10 # GPIO pin connected to the pixels (10
uses SPI /dev/spidev0.0).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually
800khz)
LED_DMA = 10 # DMA channel to use for generating
signal (try 10)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for
brightest
LED_INVERT = False # True to invert the signal (when using
NPN transistor level shift)
LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53
LED_STRIP = ws.WS2811_STRIP_GRB # Strip type and color
ordering
列表 6-2 strandtest.py 的新 LED 条配置
一旦你设置好代码,就可以运行它了。
运行示例代码
保存你对示例程序所做的更改,并使用以下命令运行它:
pi@raspberrypi:~/robot $ python3 strandtest.py -c
你可能还需要戴上太阳镜!现在你的 NeoPixel 应该会通过一系列的模式,这些模式的名称会在终端中显示出来(如图 6-9 所示)。

图 6-9 NeoPixels 在 strandtest.py 示例程序中的运行效果
当你的视网膜受够了时,按 CTRL-C 来终止示例代码。你应该在原始运行命令的末尾添加的–c参数会关闭你的 LED。如果你没有在命令中添加–c,终止程序将只是冻结你的 LED,它们会保持亮着。
如果你担心 LED 的亮度会让你眼睛刺痛,不用担心!在我们将 NeoPixel 控制添加到 Wiimote 程序时,我会向你展示如何调低它们的亮度。
使用 Wiimote 程序控制 NeoPixels
现在你已经测试了 NeoPixel 并看到了它们的能力,是时候将 LED 控制功能添加到你之前制作的基于加速度计的 Wiimote 程序中了。
我们将为 Wiimote 程序添加 NeoPixel,但最好保留原始的 Wiimote 代码副本,以防万一出现问题,或者我们以后想要恢复到原来的状态。为此,我们将创建并编辑该程序的副本。首先,确保你所在的目录是存储代码的目录;对我而言,就是我的robot目录。然后,在终端中使用 cp 命令复制原始的 Wiimote 程序:
pi@raspberrypi:~/robot $ cp remote_control_accel.py neo_remote_
control.py
这个命令简单地将第一个参数(remote_control_accel.py)的内容复制到第二个参数指定的新文件中。正如你所看到的,我决定将我的 Wiimote 程序的 NeoPixel 版本命名为neo_remote_control.py。接下来,用 Nano 打开新复制的文件,操作如下:
pi@raspberrypi:~/robot $ nano neo_remote_control.py
现在输入 Listing 6-3 中的代码修改,或者你也可以在 nostarch.com/raspirobots/ 下载完整程序。我已经省略并压缩了那些没有变化的程序部分。
import gpiozero
import cwiid
import time
➊ from rpi_ws281x import *
robot = gpiozero.Robot(left=(17,18), right=(27,22))
--snip--
wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC
LED_COUNT = 8
LED_PIN = 10
LED_FREQ_HZ = 800000
LED_DMA = 10
➋ LED_BRIGHTNESS = 150
LED_INVERT = False
LED_CHANNEL = 0
LED_STRIP = ws.WS2811_STRIP_GRB
➌ strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ,
LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP)
strip.begin()
➍ def colorWipe(strip, color, wait_ms=50):
"""Wipe color across display a pixel at a time."""
➎ for i in range(strip.numPixels()):
strip.setPixelColor(i, color)
strip.show()
time.sleep(wait_ms/1000.0)
while True:
➏ buttons = wii.state["buttons"]
if (buttons & cwiid.BTN_PLUS):
colorWipe(strip, Color(255, 0, 0)) # Red wipe
if (buttons & cwiid.BTN_HOME):
colorWipe(strip, Color(0, 255, 0)) # Blue wipe
if (buttons & cwiid.BTN_MINUS):
colorWipe(strip, Color(0, 0, 255)) # Green wipe
if (buttons & cwiid.BTN_B):
colorWipe(strip, Color(0, 0, 0)) # Blank
x = (wii.state["acc"][cwiid.X] - 95) - 25
--snip--
if (turn_value < 0.3) and (turn_value > -0.3):
robot.value = (forward_value, forward_value)
else:
robot.value = (-turn_value, turn_value)
LISTING 6-3 更新后的 Wiimote 代码,具有 NeoPixel 功能
这个程序依赖于两个额外的库,而原始的 Wiimote 代码没有使用,所以我们需要导入 time 和 rpi_ws281x 这两个库 ➊。
然后,像原始程序一样,我们设置机器人和 Wiimote 进行使用。之后,我们定义了与示例 NeoPixel 程序中看到的相同的一组常量。这些常量定义了 NeoPixel Stick 的各种参数。最显著的是,你会发现LED_BRIGHTNESS ➋,它是一个常量,可以设置在 0 到 255 之间。我将其设置为 150,使其更暗、更柔和,减少对眼睛的刺激。
在 ➌ 处,我们创建了 NeoPixel Stick 对象,并设置了之前定义的常量。库在接下来的行初始化。
然后我们定义一个名为colorWipe()的函数 ➍ 以便稍后使用。这个函数直接来自 strandtest.py 示例。函数内的注释描述了它的功能:它会一次擦除一个像素,并将颜色逐步应用到 NeoPixel 条上。为此,它接收一个 RGB color 参数,并使用 for 循环 ➎ 一次设置每个像素的颜色,中间有短暂的延迟。
然后,我们开始在无限的 while 循环中编写代码。每次循环开始时,读取 Wiimote 按钮的状态 ➏。然后,根据用户按下加号、减号或主页按钮的不同,NeoPixel 条上会逐渐显示不同的颜色,并保持该颜色,直到按下另一个按钮。如果用户按下 B 按钮,NeoPixel 将会重置。
程序的其余部分与原始程序完全相同:它处理来自控制器的加速度计输出,并使机器人相应移动。
运行你的程序:NeoPixel 和 Wiimote 控制
保存你的工作并使用以下命令运行你的代码:
pi@raspberrypi:~/robot $ python3 neo_remote_control.py
现在你的机器人应该能响应来自 Wiimote 的加速度计数据。尝试按下加号、减号、主页和 B 按钮来触发不同的灯光,如 图 6-10 所示。

图 6-10 我的机器人,NeoPixel 设置为蓝色
在通过 CTRL-C 终止程序之前,确保你按下 Wiimote 上的 B 按钮关闭 NeoPixel!
挑战自己:尝试不同的颜色和图案
一旦你玩过机器人和 NeoPixel,回到程序中,查看之前展示的示例代码,看看你能否通过更改 RGB 颜色组合来设置自己的自定义颜色。或者,看看你是否能够创造更具冒险精神的灯光图案来显示。
如果你有多个 NeoPixel 条,可以通过将一个条的输出连接到另一个条的输入来将它们连接在一起,打造一个更炫目的双轮车!
向你的树莓派机器人添加扬声器
虽然你的机器人已经取得了很大进展,但一个显著缺失的功能是能够发出声音和进行通信。在接下来的两个项目中,我们将改变这一点!我将指导你向机器人添加一个小型 3.5 毫米扬声器,并用它为之前的两个项目增加声音:为 Wiimote 程序添加车喇叭声,为障碍物避让程序添加停车传感器风格的蜂鸣声。
警告
你只有拥有像 Pi 3、Pi 2、Pi 1 Model B/B+ 或甚至 A+ 这样的全尺寸树莓派时,才能跟随这些项目。像 Pi Zero 和 Pi Zero W 这样的模型没有 3.5 毫米音频插孔,因此无法轻松连接到扬声器。
理解 3.5 毫米扬声器的工作原理
一个扬声器(或简单的音响)将电气音频信号转换成可以被人类听到的声音。你会在各种环境中见到许多扬声器——从音乐会上的巨大扬声器到手机内部的微型扬声器。
为了将电气信号转换为可听见的声音,扬声器使用电磁铁使音锥振动。这个音锥会放大振动,并将声波传递到周围的空气中,最终传到你的耳朵里。
在接下来的两个项目中,你将需要一个小型 3.5 毫米扬声器,像图 6-11 中展示的那样。3.5 毫米指的是音频插孔的直径。这个尺寸是行业标准,也与大多数手机耳机插孔相同。

图 6-11 我的 3.5 毫米小型扬声器
注意
如果你的扬声器不可充电,供电方式将取决于具体型号。如果需要 USB 电源,你可以将其插入 Pi 的 USB 端口之一。拥有可充电扬声器可以避免这个问题,因此在这种情况下,它是最理想的选择。
你可以通过在 eBay、Amazon 或任何常规电子零售商处搜索来购买一个 3.5 毫米扬声器。它的价格应该不会超过 10 美元。品牌和型号并不是特别重要;只要它足够小,能够放到你的机器人上,并且声音足够大,且有 3.5 毫米插孔,你就可以使用它!
连接你的扬声器
大多数小型扬声器都是可充电的,所以在将扬声器连接到树莓派之前,请确保它已完全充电并且可以正常工作。
你的 Pi 的 3.5 毫米音频插孔位于 HDMI 和以太网端口之间。将扬声器的 3.5 毫米电缆插入 Pi 上的插孔,如图 6-12 所示。

图 6-12 扬声器通过 3.5 毫米音频插孔连接到我的树莓派
现在将扬声器安装在你的机器人底盘的某个位置。你安装的位置取决于扬声器的大小以及你可用的空余空间。由于我没有足够的空间将扬声器直接安装到主底盘上,我决定用几块 LEGO 积木做一个小支杆,然后用粘性胶将扬声器固定在上面,正如图 6-13 所示。

图 6-13 我的 3.5 毫米扬声器连接到我的 Pi,并安装在小 LEGO 支杆上方
向 Wiimote 程序添加汽车喇叭音效
现在让我们扩展之前的程序,让你的机器人根据命令发出汽车喇叭的声音。我们将编辑 NeoPixel Wiimote 程序,使当 Wiimote 上的 A 按钮被按下时,激活喇叭音效。
安装软件
通常,你会通过在图形界面中点击音频文件并在音乐播放器应用程序中打开它来播放音频文件。但与图形界面不同,终端没有这样的功能,所以你必须使用特殊的命令来播放音频文件。与 NeoPixels 一样,你首先需要安装所需的软件并配置音频输出。
首先,确保你的树莓派上已安装 alsa-utils 软件包。这是一个与音频和设备驱动程序相关的软件集合。你可以使用以下命令检查它是否已安装,或者安装该软件包:
pi@raspberrypi:~/robot $ sudo apt-get install alsa-utils
如果你的树莓派提示你已经安装了最新版本的 alsa-utils,那就太好了!如果没有,你需要通过快速安装过程,按照提示进行操作。
完成此步骤后,剩下的唯一步骤是告诉树莓派通过 3.5 毫米音频插孔而不是 HDMI 端口播放音频。我们通过使用树莓派配置工具 raspi-config 来做到这一点,就像之前那样。要打开此工具,请使用以下命令:
pi@raspberrypi:~/robot $ sudo raspi-config
你应该看到一个蓝色的屏幕,中央有一个灰色框内的选项,如图 6-14 所示。

图 6-14 树莓派软件配置工具
现在,使用箭头键向下滚动并选择 Advanced Options,然后按 ENTER。这将打开一个新菜单;向下滚动至 Audio,选择它,并再次按 ENTER。
进入该选项后,你将看到三个选项。选择 Force 3.5mm jack 选项,如图 6-15 所示。

图 6-15 使用 raspi-config 选择音频输出
接下来,你将返回到 图 6-14 中显示的原始菜单。从那里,按右箭头键两次(以高亮 Finish),然后按 ENTER 退出配置工具。
从终端播放声音
要从终端播放声音,首先你需要一些声音文件!本项目及下一个项目的音频文件可以在线找到,网址是 nostarch.com/raspirobots/。如果你已经批量下载了所有软件,那么你应该已经拥有这些文件。或者,你也可以通过一些简单的命令从网上获取这两个音频文件。不管哪种方式,首先在你存储所有机器人程序的文件夹内创建一个名为 sounds 的新目录。对我来说,这个命令如下所示:
pi@raspberrypi:~/robot $ mkdir sounds
如果你批量下载了文件,请将 beep.wav 和 horn.wav 文件转移到这个新文件夹中。如果你想直接下载这些文件,可以按如下方式切换到该目录:
pi@raspberrypi:~/robot $ cd sounds
最后,要下载每个音频文件,请使用以下命令:
pi@raspberrypi:~/robot/sounds $ wget https://raw.githubusercontent
.com/the-raspberry-pi-guy/raspirobots/master/sounds/beep.wav
接着,输入以下命令:
pi@raspberrypi:~/robot/sounds $ wget https://raw.githubusercontent
.com/the-raspberry-pi-guy/raspirobots/master/sounds/horn.wav
现在,如果你在终端中输入ls,你将看到两个新的音频文件——horn.wav和beep.wav:
pi@raspberrypi:~/robot/sounds $ ls
horn.wav beep.wav
前者是我们将在本项目中使用的文件。在你测试horn.wav之前,使用以下命令将扬声器的软件音量调至最大:
pi@raspberrypi:~/robot/sounds $ amixer set PCM 100%
同时,确保你的 3.5 毫米扬声器上的任何物理音量控制也已调至最大。然后,为了通过 3.5 毫米扬声器播放horn.wav,你将使用aplay,一个基于终端的声音播放器,如下所示:
pi@raspberrypi:~/robot/sounds $ aplay horn.wav
正在播放 WAVE 'horn.wav':签名 24 位小端格式,3 字节,
频率 44100 Hz,立体声
你应该能听到机器人发出单一的汽车喇叭声!
使用 Wiimote 程序播放声音
现在你了解了如何通过终端播放音频文件,你可以将此功能添加到本章早些时候的 Wiimote 程序中。这意味着你的机器人不仅可以触发灯光秀,还可以在你想要的时候鸣响汽车喇叭!
为了实现这一点,我们将在 Python 中调用aplay命令。返回到robots目录,然后使用以下命令重新打开 NeoPixel/Wiimote 代码:
pi@raspberrypi:~/robot $ nano neo_remote_control.py
然后,将清单 6-4 中的新增内容添加到你的代码中。如之前一样,所有未更改的代码已被省略。或者,你可以从本书网站下载修改后的文件。
import gpiozero
import cwiid
import time
from rpi_ws281x import *
➊ import os
robot = gpiozero.Robot(left=(17,18), right=(27,22))
--snip--
while True:
buttons = wii.state["buttons"]
if (buttons & cwiid.BTN_PLUS):
colorWipe(strip, Color(255, 0, 0)) # Red wipe
--snip--
if (buttons & cwiid.BTN_B):
colorWipe(strip, Color(0, 0, 0)) # Blank
➋ if (buttons & cwiid.BTN_A):
os.system("aplay sounds/horn.wav")
x = (wii.state["acc"][cwiid.X] - 95) - 25
--snip--
if (turn_value < 0.3) and (turn_value > -0.3):
robot.value = (forward_value, forward_value)
else:
robot.value = (-turn_value, turn_value)
清单 6-4 修改后的 NeoPixel/Wiimote 代码,加入汽车喇叭声音效果
所需的新增内容很简单,仅涉及三行。首先需要注意的是在➊处,os库被导入。os库使我们能够在 Python 程序中使用树莓派操作系统的功能。
这在➋处非常有用。在这里,程序检测用户是否按下了 Wiimote 上的 A 按钮。如果是,它会使用os.system调用之前使用的相同的aplay终端命令。请注意,这里还包括了一个简短的文件路径指向horn.wav音频文件,因为这个文件存储在与程序不同的目录中。
运行你的程序:NeoPixels、声音效果和 Wiimote 控制
保存你的工作,并使用与上一个项目相同的命令运行它:
pi@raspberrypi:~/robot $ python3 neo_remote_control.py
你的机器人现在将像以前一样通过加速度计控制进行响应。你还可以像以前一样触发相同的灯光。现在尝试按下 A 按钮:你应该听到机器人鸣响喇叭!
向避障程序中添加蜂鸣声
在本项目中,我们将重新访问你在第五章中编写的避障程序,并在机器人检测到 15 厘米范围内的障碍物时添加一个蜂鸣声来提醒你。
将蜂鸣声集成到避障程序中
你已经设置好了扬声器并配置了必要的软件,所以我们可以直接开始将蜂鸣声集成到避障程序中了。
我们将像之前为喇叭所做的那样,通过在 Python 程序中调用 aplay 来实现。我建议使用 cp 来创建一个避障程序的新副本。我将我的副本命名为 beep_obstacle_avoider.py。请输入我所做的修改,如清单 6-5 所示。
import gpiozero
import time
➊ import os
TRIG = 23
ECHO = 24
trigger = gpiozero.OutputDevice(TRIG)
--snip--
while True:
dist = get_distance(trigger,echo)
if dist <= 15:
➋ os.system("aplay sounds/beep.wav")
robot.right(0.3)
time.sleep(0.25)
else:
robot.forward(0.3)
time.sleep(0.1)
清单 6-5 beep_obstacle_avoider.py 程序
就像之前一样,我们导入 os 模块 ➊。然后,如果传感器检测到距离小于或等于 15 厘米的物体,程序会播放蜂鸣声 ➋,并且机器人改变方向。
运行你的程序:避障时发出蜂鸣声
保存你的工作并使用以下命令运行:
pi@raspberrypi:~/robot $ python3 beep_obstacle_avoider.py
现在你的机器人会避开障碍物,并在此过程中发出蜂鸣声!
挑战自己:为你的其他项目添加音效
现在你已经了解了将音效添加到程序中的相对简单过程,为什么不回顾一下你在本书中编写的其他程序,并为它们添加声音呢?你可以用手机录制自己的声音,或者使用提供免费音频文件的在线音效库。例如,可以查看 Freesound: freesound.org/。
总结
在本章中,你为你的机器人装上了超亮的 NeoPixels,并赋予了它声音的能力!在三个不同的项目中,我们从 RGB LED 的理论到如何在终端播放音频,都做了详细讲解。
在下一章中,我们将使你的机器人更加智能!我将指导你完成让你的两轮车能够自主跟随路线的过程。
第七章:跟踪线
本章中,你将赋予机器人检测并自动跟随一条线的能力。它将能够识别自己的路径,然后决定如何精确地坚持走下去。
这是一次对数字识别和巧妙编程的测试。它也是一个经典的机器人任务,对于每个人来说,从初学者到专业人士都很重要。完成这个项目后,你将拥有一个完全自主的机器人,它将能够像胶水一样坚持沿着线行驶!
创建轨道
像往常一样,在开始任何项目之前,重要且有用的是退后一步,分析当前的任务。这里的目标是让你的机器人沿着一条线行驶。更具体地说,你希望让机器人沿着一个白色背景上的黑色线条行驶,像图 7-1 中所示的那样。

图 7-1 我的机器人沿着黑线行驶
白色和黑色的组合提供了最大的对比度,帮助你的机器人使用简单的跟踪传感器。
第一步是为你的机器人创建一条它可以跟随的线。你可以随意设计轨道的形状,最简单的选项是一个基本的环形,但只要背景是白色的,线条是黑色的,尽管发挥创意。我还建议将线条的宽度设定为大约 1/4 英寸。
创建轨道有很多不同的方法。你可以简单地拿一大张纸(至少是账单大小,大约 11 × 17 英寸),用黑色马克笔画上一条粗线。你也可以用一些黑色电工胶带贴在白色海报板上。你甚至可以在线购买现成的跟踪轨道。如果你有打印机,我建议在信纸大小的纸上打印出轨道,然后用胶带把它们拼接起来。
我还在本书的资源中提供了一个模板,供你制作成任意形状的轨道,你可以在 Windows、Mac 或 Linux 电脑上访问:
-
如果你还没有这样做,下载软件包到你的个人电脑,网址是 https://nostarch.com/raspirobots/。
-
转到存储软件的文件夹,然后打开名为track_generator.pdf的 PDF 文件。这是一个 34 页的文档,包含了许多 20 × 20 厘米的瓷砖,上面有不同的线条(见图 7-2)。
![image]()
图 7-2 track_generator.pdf 文档
-
打印出你想要拼接成轨道的线条,剪下来,然后把它们粘在一起,组成你自己的自定义轨道。PDF 文档的前几页展示了简单的路径,如直线和拐角,但往下滚动,你会看到越来越复杂的路径!
对于你的第一个轨道,我建议保持相对简单。记住,你可以随时打印出更多瓷砖,并在未来为你的机器人设计一个更难的课程。
-
为了创建一个简单的环形轨道,像图 7-3 所示那样,打印出四份瓷砖类型#2(直线)和四份瓷砖类型#3(基本转角)。你应该能够通过 PDF 阅读器软件的打印对话框专门打印这些页面。确保每块瓷砖占用一张信纸大小的纸张。
-
使用剪刀沿着每块瓷砖的虚线剪开。然后按照图 7-3 所示将它们排列成环形,并沿着底面的长度使用胶带将瓷砖的边缘连接在一起。你的轨道现在已经完成!
警告
确保在连接瓷砖时不要把胶带贴在黑线上的位置,因为这可能会影响传感器的性能。同时尽量消除瓷砖之间的任何缝隙或褶皱——这些都会妨碍机器人运动!

图 7-3 我组装的基本跟踪轨道
跟踪线路背后的理论
我们将使用红外(IR)传感器让你的 Raspberry Pi 机器人跟踪黑色线条。在第五章中,我们使用类似的技术来避障,当时我们使用超声波来检测物体。但在这一章,我们将使用不可见的光线,而不是声音。幸运的是,你之前学到的很多理论也可以在这里应用。
每个 IR 传感器,如图 7-4 中的传感器,都有两个小的灯泡状装置——一个红外发射器和一个接收器,通常安排并紧密地放置在一起。发射器是一个 IR LED,当被触发时,会发射一个红外光脉冲。接收器是一个 IR 光电二极管,等待接收到发射的光。光电二极管只是一个利用光线改变电流的装置。

图 7-4 一个 IR 传感器
光与不同类型的表面之间的相互作用是不同的。最明显的是,光在白色表面上反射更多,而在黑色表面上几乎完全被吸收,这使得 IR 传感器能够检测到白色背景上的黑色线条。
如图 7-5 所示,如果 IR 传感器模块位于白色表面上,接收器将检测到发射器发出的红外光束的反射。如果传感器位于黑色表面上,比如你的轨道上的线,接收器将无法检测到反射。反射率的差异使得传感器模块能够检测到前方是否有线条。

图 7-5 红外光遇到白色与黑色表面的不同表现
将一个红外传感器安装在机器人底部,可以让它检测到黑色线条的存在,但如果机器人移动使得传感器不再直接位于线条上,它很容易偏离轨道。只有一个传感器,机器人无法轻松地检测自己是否已经偏离了线条的左侧或右侧。因此,我们将使用两个红外传感器,分别安装在机器人底部的前方,约一英寸的间距。两个传感器将提供一个反馈机制,帮助机器人判断方向。这些传感器的输出有四种可能,每种情况都会指导机器人。
-
如果两个传感器都接收到反射信号并且检测到白色,机器人可以认为线条位于两个传感器之间。因此,机器人应沿直线向前移动(见图 7-6)。
![image]()
图 7-6 当两个传感器都检测到白色时,机器人向前移动。
-
如果左侧传感器没有接收到反射信号,而右侧传感器接收到了,这就意味着左侧传感器检测到了线条。这表明机器人可能偏离了轨道向右,因此应该向左转以纠正自己,如图 7-7 所示。
-
如果右侧传感器检测到线条而左侧传感器没有,机器人应该通过向右转来纠正自己,如图 7-7 底部所示。
![image]()
图 7-7 如果其中一个传感器检测到黑色线条,机器人会向左或向右转动。
-
最后,如果两个传感器都没有收到反射信号,那么它们都应该检测到黑色,如图 7-8 所示(如果你使用的是基础的环形轨道,这种情况不会发生)。接下来该做什么由你决定,但一个选择是让机器人停止。如果你尝试其他轨道布局——例如,数字 8 形状——你可能会遇到两个传感器都检测到黑色的情况。在这种情况下,你可能希望机器人前进、转弯,甚至倒退——试试看,找到最合适的方案!

图 7-8 如果两个传感器都检测到黑色,机器人会停止。
使用红外传感器检测线条
在你开始将两个红外传感器安装到树莓派并配置完整的跟线机器人代码之前,让我们先连接一个红外传感器并测试它的线条检测反应。
部件清单
在这个项目部分,你只需要使用一个传感器,但请确保购买两个,因为下一个项目中你会需要两个!
-
2 个基于 TCRT5000 的红外线跟踪传感器模块
-
跳线
基于 TCRT5000 的线路跟踪传感器模块,如图 7-9 中所示,非常常见,可以在网上以不到几美元的价格购买。我是通过在 eBay 上搜索“TCRT5000 线路跟随模块”购买的。传感器名称中的TCRT5000部分指的是红外光学传感器,即电路板底部的小黑色组件。

图 7-9 我的 TCRT5000 红外线跟踪传感器模块
请确保获取像图 7-9 中所示的线路跟踪模块,因为这意味着光学传感器的功能已经被整齐地封装成一个易于使用的组件。这些板有一组简单的引脚,只需要三个连接(参见图 7-10)。

图 7-10 TCRT5000 红外传感器模块的引脚图
红外二极管被封装在小黑色组件内部,并在模块连接电源时持续发射红外光。如果光线没有反射回传感器,说明必须存在一条黑线,并且模块的输出引脚(OUT)会变低(即电压下降)。这种简单的数字逻辑非常理想,更棒的是,模块可以通过 Pi 的 3.3 V 电源供电。这样我们就不必像在第五章中为超声波距离传感器所做的那样使用电压分压电路了。
注意
记住,您无需断开之前的任何电路,但我不会在这里显示这些连接。
接线您的 TCRT5000 线路跟踪传感器模块
断开树莓派的电源,并按照以下说明连接您的传感器:
-
使用一根 F-F 跳线将 TCRT5000 模块的 VCC 引脚连接到树莓派的物理引脚 1。这是 +3.3 V 连接,提供传感器的电源。
-
使用另一根跳线将模块的 GND 引脚连接到面包板上的公共接地轨道。到目前为止,您的接线应该像图 7-11 所示。
![image]()
图 7-11 线路跟踪传感器连接到 +3.3 V 和 GND
-
使用另一根跳线将传感器的数据输出引脚(OUT)连接到树莓派的物理引脚 21。这是 BCM 9。您的完整电路应该像图 7-12 所示。

图 7-12 完整的面包板电路图,展示了您的 TCRT5000 线路跟踪传感器模块已经接线并就位
编程您的树莓派以检测线路
现在您已经将线路传感器连接到树莓派,让我们编写一些代码来测试其线路检测响应。通过墙壁插座为树莓派供电,启动它并进入代码文件夹,然后输入以下命令创建并打开一个名为line_test.py的测试程序:
pi@raspberrypi:~/robot $ nano line_test.py
添加清单 7-1 中的代码,这将测试你的 TCRT5000 模块。该程序的目的是仅仅输出到终端,告知用户模块是否检测到了一条线。
import gpiozero
import time
➊ line_sensor = gpiozero.DigitalInputDevice(9)
while True:
➋ if line_sensor.is_active == False:
print("Line detected")
➌ else:
print("No line detected")
time.sleep(0.2)
清单 7-1 检测一条线
在导入常用库之后,我们将线传感器设置为 BCM 9 上的数字输入 ➊。
注意
TCRT5000 的检测距离在 1 毫米到 8 毫米之间。如果线条距离传感器太远,它可能会出现误报或漏报。
然后我们开始一个无限的while True循环,包含程序的逻辑。在 ➋ 处,我们使用if语句来检测线传感器是否处于活动状态。如果它没有处于活动状态,必须意味着红外反射没有返回,因此发射的光线已经被黑线吸收。所以,线条已经被检测到,并且我们通过if语句内的print()语句告知用户。
任何其他情况都意味着线传感器是活动的,因此没有检测到一条线。else语句 ➌ 捕获了这种替代情况,并输出到用户,告知没有检测到线。程序随后等待五分之一秒并重新开始循环。
运行你的程序:检测一条线!
保存程序后,拿一段轨道来测试你的传感器。要运行程序,输入:
pi@raspberrypi:~/robot $ python3 line_test.py
当传感器周围没有任何物体时,可能会产生不稳定的结果,这些结果会显示在终端中。将你的轨道带到模块上并移动线条到传感器上。你应该会注意到,随着你移动轨道,终端输出会变化为Line detected:
pi@raspberrypi:~/robot $ python3 line_test.py
No line detected
No line detected
Line detected
Line detected
我的传感器上也有一个 LED 灯,当线条出现在视野中时,它会改变状态。
如果你遇到模块问题,且它没有很好地检测到线条,可以尝试几种方法。首先,尝试通过关闭灯光来限制来自其他光源的干扰。或者,一些 TCRT5000 模块上有一个内置的电位器,用于调整灵敏度。这个电位器通常看起来像一块蓝白色的塑料,上面有一个可以插入螺丝刀的地方。使用合适的螺丝刀或其他工具来旋转这个电位器,看看是否能改善你的读数。
让你的机器人自主跟踪一条线
当你的传感器成功检测到线条时,就该给你的机器人增加跟踪轨迹的能力了。
在本项目结束时,你将连接上第二个传感器,并编写完整的自主程序逻辑,打造一台能够跟踪线路的机器人。
连接第二个 TCRT5000 线跟踪传感器模块
你已经连接了第一个 TCRT5000 模块,现在只需连接第二个模块。如果第一个模块没有连接,请翻回几页,按照之前项目中的接线指南进行操作。
连接第二个传感器的过程如下:
-
拿一根 F-F 跳线,将第二个 TCRT5000 模块的 VCC 引脚连接到 Raspberry Pi 上的物理引脚 17。这是另一个 +3.3 V 引脚,将为传感器提供电源。
-
现在,使用一根跳线将新模块的 GND 引脚连接到面包板上的公共地轨。
-
使用一根电线将第二个传感器的数据输出引脚(OUT)连接到 Raspberry Pi 的物理引脚 23。这是 BCM 11。第二个传感器的接线(省略第一个传感器)应类似于图 7-13 所示。

图 7-13 第二个线路跟踪传感器连接到电源、地和数据
将两个线路跟踪传感器连接后,你的面包板应该像图 7-14 一样。

图 7-14 两个线路跟踪传感器连接到 Raspberry Pi
安装你的传感器
现在你需要将 TCRT5000 模块安装到机器人前部的底面。
为了避免以后修改代码示例,确保你首先连接的 TCRT5000 模块(连接到 BCM 9 的那个)位于机器人左侧,第二个 TCRT5000 模块(连接到 BCM 11 的那个)位于机器人右侧。
你可以根据自己的需求将这些传感器安装到底盘上。如果你使用的是像我一样的 LEGO 机器人,建议将两个由 2×2 LEGO 块组成的小支架固定到底盘底部;我的支架大约有四个块高。你还可以使用粘性胶将模块固定在支架底部,就像我做的那样(见图 7-15)。我已经将传感器的电线穿过 LEGO 底盘中间的空隙。

图 7-15 我安装在 LEGO 支架上的红外传感器,位于机器人底部
安装模块时,请记住,从光学传感器到地面的最佳距离范围为 1 毫米至 8 毫米。同时还要记住,它们之间的间隙越大,你的机器人偏离线路的幅度就越大,直到它纠正自己。作为参考,我的传感器彼此之间仅相隔一到两英寸,并且分别放置在前部稳定器的两侧。
编程让你的机器人沿线行驶
当你的传感器都已连接并安装到位时,接下来是编写代码,让你的机器人能够沿着线路行驶。
使用 Nano 打开一个新的程序,并命名为 line_follower.py,如下所示:
pi@raspberrypi:~/robot $ nano line_follower.py
清单 7-2 中的代码将我们之前讨论的线路跟踪的理论和过程付诸实践。在继续讲解之前,花点时间查看一下代码。
import gpiozero
➊ SPEED = 0.25
robot = gpiozero.Robot(left=(17,18), right=(27,22))
➋ left = gpiozero.DigitalInputDevice(9)
right = gpiozero.DigitalInputDevice(11)
while True:
➌ if (left.is_active == True) and (right.is_active == True):
robot.forward(SPEED)
➍ elif (left.is_active == False) and (right.is_active == True):
robot.right(SPEED)
➎ elif (left.is_active == True) and (right.is_active == False):
robot.left(SPEED)
➏ else:
robot.stop()
清单 7-2 沿线路行驶
这里的代码遵循与本书中之前项目相同的逻辑布局。我们导入gpiozero,然后初始化一个常量SPEED,并将其设置为 0.25 ➊。这个值表示机器人在整个程序中的速度,可以设置为 0 到 1 之间的任何值。
当你第一次运行这段代码时,你会发现机器人行驶速度对其循迹能力有巨大影响。通过在程序开始时定义一个常量,你可以轻松地调整这个设置,而无需在后续的代码中翻找。
在➋处,我们将第一个 TCRT5000 传感器设置为数字输入,并将其赋值给变量left。然后我们对第二个循迹传感器执行相同操作,将其赋值给变量right。
然后,我们开始一个无限的while True循环,包含程序的主要逻辑:一系列的if语句。这里就是实现循迹理论的地方。
在➌处的代码处理了两传感器都活跃并且都读取到白色的情况。在没有检测到黑线的情况下,程序假设黑线就在传感器下方,并且机器人按照给定速度向前行驶。
接下来,一个elif语句 ➍ 捕捉到左传感器关闭并检测到黑色,而右传感器活跃并检测到白色的情况。在这种情况下,我们需要执行纠正操作,使机器人右转。
然后,几乎相同的elif语句 ➎ 处理右传感器检测到黑线的情况。这时,纠正操作使机器人左转。
最后,在➏处我们使用else语句处理剩下的唯一选项:两个传感器都不活跃,因此都读取为黑色。机器人在此之后的具体行为由你来定义。在我的代码中,我决定停止它的运动。
运行你的程序:让你的机器人沿线行驶!
现在,随着你的循迹程序完成,将机器人连接到电池电源,并将其放置在你先前创建的测试轨道上。为了获得最佳效果,确保黑线正好位于机器人下方,并且在两个 TCRT5000 传感器之间(参见图 7-16)。

图 7-16 我的机器人就位,准备沿线行驶
使用以下命令运行程序:
pi@raspberrypi:~/robot $ python3 line_follower.py
你的机器人现在应该能够完全自主地沿着轨道行驶,并且毫无问题地跟随黑线。看着机器人在无尽的循环中快速穿行,欣赏你的成果吧!
注意
你可能会发现需要将轨道粘贴到地板上,以防止机器人轮子将其移位。如果是这种情况,只需用胶带将轨道固定好,确保稳固且不永久性固定。
循迹实验
线路跟踪是机器人学中的经典课程,但正如你可能已经察觉到的,它可能需要大量的调整和修改才能提高效果和结果。你可能已经注意到,你可以通过改变许多不同的因素来改变线路跟踪器的性能。以下是我的一些建议。
改变赛道
虽然简单的回路是一个很好的初次测试平台,但它很快就会变得无聊。为了挑战你的机器人,试着创造一个更具冒险性的赛道。使用更紧的转弯、更长的直线和更复杂的几何形状!你甚至可以从真实的赛道中获得灵感——例如,见图 7-17 中的摩纳哥大奖赛赛道(Figure 7-17)。

图 7-17 摩纳哥大奖赛赛道表示为一条黑线,你的机器人可以沿着这条线行驶
改变速度
你的机器人在赛道上行驶得越快,它对 TCRT5000 传感器提供的信息反应的时间就越少。在更快的速度下,你可能会发现机器人会偏离线路。你可以通过进入程序,编辑代码顶部定义的SPEED常量来改变机器人的速度。
你也可能会发现,你想要为不同的动作调整线路跟踪器的速度。例如,当机器人绕过转弯时,可能需要慢一点。你可以通过在程序中创建另一个常量CORNER_SPEED并将其应用到左右转弯的函数中来实现这一功能。
当你微调你的线路跟踪机器人速度时,计时它绕赛道行驶的时间。看看你能让它多快地精确跟踪线路。你甚至可以和朋友们比赛,举办一场线路跟踪竞赛,看看谁的代码最好。
改变传感器的位置
红外传感器之间的距离越远,你的机器人偏离线路的距离就越大,直到执行修正动作。这可能会导致你的机器人沿着线路呈之字形打滑。试着将模块放得更近,看看这会如何影响你的线路跟踪器的表现。
你应该会发现,当模块放得更近时,机器人会更多地左右转动以重新回到轨道。这意味着你的机器人会更精确地跟踪线路,但这会有什么代价呢?它是否会影响机器人完成赛道的速度?动动脑筋,试试看吧!
添加更多传感器
如果你想进一步提升,可以添加更多的线路跟踪传感器。就像避障一样,机器人对于自身位置的信息越多,背后的程序就越智能。如果你能够添加第三、第四甚至第五个 TCRT5000 模块,那么你就可以判断机器人偏离线路的程度。然后,你可以利用这些信息来调整修正动作的幅度。例如,如果机器人偏离线路较远,它可以执行更快速的修正操作。
总结
在这一章中,你已经赋予了你的机器人自主跟踪一条线路的能力。我们涵盖了从线路跟踪的理论到所需传感器以及它们背后的代码的所有内容。
在下一章中,我将向你展示如何使用官方的树莓派相机模块来识别和跟踪一个彩色球!
第八章:计算机视觉:跟踪一个彩色球
作为人类,我们通过眼睛和大脑来看待和理解周围的世界。虽然这一过程对我们来说是自动发生的,但视觉实际上是一个极为复杂的过程。
计算机视觉是计算机科学和工程的一个高级领域,旨在使计算机和机器能够像人类一样,甚至更好地“看”和理解周围环境。在本章中,你将学习一些计算机视觉的原理,然后我会展示如何使用摄像头让你的机器人识别并跟踪一个彩色球。
计算机视觉过程
想象一下观察、识别和反应于一个彩色物体的过程。首先,物体的图像通过你的眼睛传到视网膜。视网膜进行一些基础分析,然后将接收到的光转化为神经信号,这些信号被发送到大脑,并由视觉皮层进行彻底分析。然后,大脑识别出物体并发出指令给你的肌肉。
令人惊讶的是,这一切发生在极短的时间内,并且不需要任何意识上的努力。
即使是这样简化的解释,你也能感受到视觉的复杂性。让计算机完成类似的任务,正是计算机视觉领域的专家们不懈努力的目标,几十年来他们都在为此奋斗。
任何计算机视觉系统必须能够完成三项任务:
看 生物体通常通过眼睛来看。计算机必须使用它们的数字等价物:摄像头。摄像头通过镜头将光线聚焦到数字传感器上。该传感器随后将光线转化为数字信息:图像或视频帧。
处理 输入捕获后,必须对其进行处理以提取信息、识别模式和操作数据。在自然界中,这是大脑的功能。对于计算机视觉来说,这由代码和算法来完成。
理解 然后,信息必须被理解。计算机可能已经检测并处理了一个模式,但这个模式是什么,它意味着什么?同样,这个重要步骤依赖于代码和算法。
当这三个元素协同工作时,计算机就能处理各种基于视觉的问题,包括我们在本章中要解决的问题:我们将赋予你的机器人检测、识别并朝着一个可能出现在其周围环境中的彩色球移动的能力。
部件清单
你需要为下一个项目准备两样新物品:
-
一个彩色球
-
标准 Pi 摄像头模块
最初,你还需要访问另一台计算机来远程查看在本项目配置阶段通过 Pi 摄像头模块拍摄的图像。这可以是你用来通过 SSH 连接到 Pi 的计算机。如果你在本书的过程中没有使用过 SSH,那么你可以在配置时直接将 Pi 连接到 HDMI 显示器上。
让我们更仔细地看看新的部件。
目标:彩色球
首先,你需要一个彩色球作为你的机器人要寻找并跟随的目标。你的球应该是一个明亮的颜色,在房间里不常见,以帮助你的机器人将其与其他物体区分开来。我建议使用一些独特且不太大的球,比如图 8-1 中显示的球。我使用的是一个大约 2 英寸直径的亮黄色减压球。你可能已经有类似的物品放在家里,如果没有,你应该能在网上以几美元的价格买到一个类似的。

图 8-1 作为目标的彩色球示例;我使用的是左边的黄色球。
官方树莓派相机模块
为了让你的机器人具备视觉能力,你需要一台相机。在这个项目中,我们将使用官方的树莓派相机模块,如图 8-2 所示。

图 8-2 官方树莓派相机模块
相机模块是一个由树莓派基金会设计和生产的树莓派扩展板。最新型号配备了一个 800 万像素的传感器,尺寸不到 1 英寸见方!它不仅能够拍摄出色的静态照片,还可以以每秒 30 帧的速度录制全高清视频。如果你使用的是旧款 500 万像素的型号,不用担心:它完全兼容这个项目,并且用法完全相同。
相机模块上的 6 英寸带状电缆连接到树莓派上的 CSI(相机串行接口)端口,如图 8-3 所示。它与所有模型兼容,包括最新版本的 Pi Zero。

图 8-3 树莓派上的 CSI 接口端口
注意
Pi Zero 采用的是迷你 CSI 接口,而不是其他所有树莓派型号上常见的标准尺寸接口。为了将相机模块连接到 Pi Zero,你还需要购买一个迷你 CSI 到 CSI 的连接线。这些通常在网上被标记为“Pi Zero 相机电缆”,价格大约是 5 美元。请记住,这个项目需要强大的图像处理能力和代码,运行速度较快的标准尺寸树莓派模型比 Zero 或原始树莓派模型表现得更好。
你可以通过常规的零售商在线购买官方树莓派相机模块,价格大约为 30 美元。
在网上查看时,你可能会注意到实际上有两种不同的官方相机模块:普通相机和NoIR版本,后者可以用于夜视。你需要的是标准相机模块。通过颜色差异,你可以轻松区分这两个板子:普通相机模块的电路板是绿色的,而 NoIR 模块是黑色的。
连接和设置你的相机模块
在安装相机模块之前,请确保你的树莓派已经关闭。然后按照以下步骤进行操作:
-
定位树莓派上的 CSI 接口。对于所有全尺寸的树莓派模型,它位于 HDMI 接口和 3.5 毫米音频插孔之间,并且清晰标注为 CAMERA。
-
接下来,通过轻轻但坚定地从两侧抓住接口并向上拉,打开端口(请参见 图 8-4)。这是一个细致的操作,通常最好将指甲插到两侧下方。image
图 8-4 打开的 CSI 接口,用于插入电缆
-
将相机模块的排线完全插入 CSI 接口,银色接触点朝 远离 3.5 毫米音频插孔和以太网端口的一侧(请参见 图 8-5)。这个方向非常关键:如果您反方向插入模块的电缆,它将无法正确连接,您将无法使用它!!image
图 8-5 CSI 接口,正确方向插入相机模块的排线
-
然后,在保持排线固定的同时,用手指按住 CSI 接口的两侧,同时将其压回到原位。如果两侧没有同时关闭,则一侧可能无法正确关闭,电缆也可能会松动。图 8-6 显示了一个正确连接的排线。请注意,银色接触点的一部分刚好可见,并且它们与板子平行。image
图 8-6 我的正确连接的相机模块排线
-
最后,为了确保相机模块正确连接,轻轻拉一下接近 CSI 接口的排线。它应该保持固定不动。如果电缆松脱或滑动,不要担心——只需将其取下并重复这些步骤。
如果您想将相机模块连接到树莓派 Zero,过程类似。找到板子右侧的 mini-CSI 接口,并用手指从两侧将其打开。然后,确保在插入 Pi Zero 相机电缆时,银色接触点朝下,朝向板子。请参见 图 8-7。

图 8-7 树莓派 Zero 型号上 mini-CSI 接口的相机电缆正确插入方向
安装您的相机
现在,相机已经连接到机器人上的树莓派,您需要将其安装在合适的位置。我建议使用一些粘土将其固定在机器人前方,放置较低的位置以确保有清晰的视野。为此,我使用了一个 2 × 2 的 LEGO 积木来创建安装空间(请参见 图 8-8)。同时,确保相机的方向与我的照片中一样正确。

图 8-8 我的相机模块安装在我的树莓派机器人上
相机模块非常脆弱,请小心处理。尽量避免扭曲电缆,并确保不要使电缆出现弯折。如果在任何时候,排线从树莓派松脱,您可以按照原来的方式重新连接。如果它从相机模块上的连接器松脱,您也可以重新连接,方法与之前相同:使用手指轻轻打开模块的 CSI 端口,然后将电缆插入,确保银色接触点朝下并朝向 PCB。
启用相机和 VNC,并设置屏幕分辨率
要在 Raspbian 中使用相机,首先需要启用它。如果您按照第一章中的所有步骤操作,您已经完成了部分工作。此外,我们还需要启用 VNC 并手动设置正确的屏幕分辨率。以下是完整的操作流程。
要进行此设置,我们将使用配置工具raspi-config。打开命令行并输入以下命令:
pi@raspberrypi:~/robot $ sudo raspi-config
您应该会看到您之前配置树莓派音频输出时看到的相同的蓝色配置屏幕。使用箭头键向下滚动至接口选项,然后按 ENTER 键。这将打开一个新的菜单,如图 8-9 所示。

图 8-9 raspi-config工具的接口选项菜单
再次按 ENTER 键选择相机。然后,系统会询问是否启用相机接口,使用左右箭头键选择是(见图 8-10)。

图 8-10 使用raspi-config启用相机
您将看到一条确认消息,表示相机接口已启用,然后您将返回原始菜单。
在raspi-config工具中时,确保 VNC 已经启用也非常重要。VNC 将在下一节中进行详细说明,但现在只需再次向下滚动至接口选项,然后选择VNC(见图 8-11)。按 ENTER 键启用它。

图 8-11 从接口选项中选择 VNC
系统会将您带回原始菜单。在您退出配置工具之前,必须做最后一件事:手动设置您的树莓派的屏幕分辨率。这将确保在稍后使用 VNC 时,屏幕能够以正确的方式显示。要设置分辨率,从原始菜单中,向下滚动至高级选项,然后继续向下滚动并选择分辨率(见图 8-12)。

图 8-12 高级选项中的屏幕分辨率设置
注意
如果你知道你电脑屏幕的分辨率 低于 全高清,请将 Pi 的屏幕分辨率设置为菜单中最接近的较低选项。你可以随时再次运行 raspi-config 来更改分辨率。
然后,系统会提示你选择一个屏幕分辨率。使用箭头键向下滚动,选择全高清选项。它看起来像是“DMT 模式 82 1920x1080 60Hz 16:9”。按下 ENTER 键选择这个选项,屏幕分辨率应该已经设置好了!你将返回到原始菜单。
按右箭头键两次(高亮显示 完成),然后按 ENTER 键退出配置工具。如果提示,请重新启动你的 Raspberry Pi。
拍摄测试照片
连接并启用相机模块后,我们来测试一下拍照。这可以通过远程终端用一个简单的命令轻松完成,但通过这种方式你无法在基于文本的环境中查看拍摄的图片!这时,VNC——你之前启用的选项——派上了用场。
使用 VNC 远程控制 Pi 的桌面
VNC 代表 虚拟网络计算。它允许你远程查看和控制 Raspberry Pi 的桌面,就像你之前使用 SSH 连接时一样,但它是针对完整的图形用户界面(GUI),而不仅仅是终端。由于我们可以通过 VNC 查看 Pi 的图形界面,你将能够轻松查看你用 Raspberry Pi 相机模块拍摄的任何照片,使用 Raspbian 内置的图像查看器。
注意
如果你按照本书的步骤操作,并且没有通过 SSH 无线连接 Raspberry Pi,不用担心!你仍然可以继续按照本节后的步骤操作,并在 Pi 连接到 HDMI 显示器后查看结果。
安装并使用 VNC Viewer 进行连接
你已经在 Raspberry Pi 端完成了所有设置,现在你需要在要查看图像的电脑上下载 VNC Viewer。我们将使用 RealVNC 提供的免费软件 VNC Viewer,它兼容 Windows、Mac、Linux 等平台。要安装该软件,请在你的机器上按照以下步骤操作:
-
在你的电脑上,打开一个网页浏览器并访问
www.realvnc.com/en/connect/download/viewer/。你应该会看到 VNC Viewer 软件的下载页面,如 图 8-13 所示。![image]()
图 8-13 VNC Viewer 软件下载页面
-
在这里,选择你的操作系统并点击 下载 按钮。软件下载完成后,按照安装向导进行操作,并同意服务条款。几分钟后,一切应该安装完毕并准备就绪!
现在已经安装了 VNC Viewer,运行它。你应该会看到一个窗口,顶部有一个框(图 8-14);在这里,你需要输入 Raspberry Pi 的 IP 地址,你应该已经知道这个地址,因为你一直在通过 SSH 连接到你的 Pi。
会弹出一个认证框,要求你输入用户名和密码。输入你的树莓派登录信息,然后点击确定。如果你没有更改默认用户,那么用户名是pi,密码是你在第一章中设置的密码。

图 8-14 设置 VNC 查看器以连接我的树莓派
一个新窗口将显示你的树莓派桌面(见图 8-15)。在这里,你可以像树莓派接入 HDMI 显示器一样访问和使用所有功能。

图 8-15 在树莓派桌面环境中,通过 VNC 查看的终端和文件管理器
使用树莓派摄像头模块拍照和查看照片
现在你已经设置好了一切,接下来可以拍摄测试照片了!我们将使用一个内置的命令行工具,叫做raspistill。通过 SSH 连接或者使用 VNC 连接中的终端窗口打开一个终端,输入以下命令拍照:
pi@raspberrypi:~ $ raspistill –o test.jpg
在 5 秒钟的延迟后(确保你可以站到相机前面或者调整好镜头),命令会执行完毕。如果你没有看到任何输出,说明一切正常!这个命令没有成功消息。这个指令会拍照并将照片保存为test.jpg,保存在命令运行的目录中——在本例中,是默认的主目录。
要在 VNC 桌面中查看图像,点击 VNC 桌面环境中的文件管理器图标(它看起来像一个文件夹集合,如图 8-16 所示)。
相机故障排除
如果运行raspistill命令时出现类似以下的可怕错误,不用担心!
pi@raspberrypi:~ $ raspistill -o test.jpg
mmal: mmal_vc_component_enable: failed to enable component:
ENOSPC
mmal: camera component couldn’t be enabled
mmal: main: Failed to create camera component
mmal: Failed to run camera app. Please check for firmware
updates
你很可能只是没有正确连接相机。如果你收到这个错误消息,或者其他任何错误,检查一下相机模块和树莓派之间的排线连接。同时,确保你已经正确启用了相机接口——返回第 172 页查阅指导。

图 8-16 文件管理器图标
导航到运行raspistill命令的目录(我是在默认的主目录中运行的),找到test.jpg文件并双击它。你应该能够在图像查看器中看到你刚拍的照片(见图 8-17)。


图 8-17 Raspbian 图像查看器中的test.jpg图像(上图);展示了一个订书机、卡尔·萨根的宇宙以及两个稍后使用的彩色球(下图)
让你的机器人寻找并追踪一个球
现在你已经连接好相机并成功完成了图像测试,是时候进入本章的高级项目:让你的机器人识别并跟踪一个彩色球了。但在此之前:我们先来快速了解一些重要的理论。
理解彩色物体识别的原理
我们如何让一个无法独立思考的机器人识别并识别出特定的物体呢?
当你的机器人移动时,球相对于机器人的位置会不断变化,因此我们首先需要的是一个不断刷新的视图,显示机器人前方的情况。相机模块通过一系列图像提供这个视图,这些图像通常被称为视频帧或简称帧。
每一张图像,如 图 8-18 中的图像,都需要进行分析,以确定它是否包含你的彩色球。为此,我们将应用各种图像处理技术。

图 8-18 来自相机模块的未处理图像,准备进行分析
第一步是将图像从 RGB 格式转换为HSV 格式。我们在 第六章中讨论了 RGB,但我在这里简要总结一下。RGB 代表红色、绿色和蓝色。来自 图 8-18 中相机模块的每个像素都是这三种颜色的组合,表示为三个介于 0 到 255 之间的数字——例如,[100,200,150]。
计算机使用 RGB 来显示颜色,但在处理图像及其包含的颜色数据时,HSV 颜色格式更为合适。HSV 代表色相、饱和度和值,它是以三种参数数字化表示颜色的另一种方式。HSV 比 RGB 更难理解和表示,但当把它看作一个圆柱体时(见 图 8-19),通常最容易理解。

图 8-19 HSV 圆柱体
色相 是 HSV 模型中的颜色部分,它表示为 0 到 360 度之间的数字。这个范围的不同部分代表不同的颜色(见 表 8-1)。
表 8-1 HSV 的色相范围
| 颜色 | 角度 |
|---|---|
| 红色 | 0–60 |
| 黄色 | 60–120 |
| 绿色 | 120–180 |
| 青色 | 180–240 |
| 蓝色 | 240–300 |
| 品红色 | 300–360 |
饱和度 是颜色中的白色程度,范围从 0 到 100%。值 与饱和度一起工作,可以看作是亮度;它描述了颜色的强度,范围从 0 到 100%。
通过将每张图像转换为 HSV 格式,你的 Pi 可以将颜色成分(色相)分离出来进行进一步分析。这意味着,无论环境和光照效果如何,计算机仍然能够识别彩色物体。这在 RGB 颜色空间中是非常难以实现的。图 8-20 显示了 HSV 数据的 RGB 实现。

图 8-20 图像的 HSV 数据
如图 8-20 所示,我的机器人将跟随的黄色球现在清晰可见,且非常独特。它不可能与背后的红球或画面中的其他物体混淆。不过,请记住,这是 HSV 颜色模型的 RGB 实现。颜色的色调值是我们无法像用眼睛看到的那样直接识别的。
接下来的步骤是查找并识别任何与我们搜索的颜色匹配的区域。在我的案例中,我想匹配图像中与我的黄色球颜色相同的所有部分。这形成了一个遮罩(参见图 8-21),它仅保留我们需要的图像部分,去除我们不需要的部分。你可以看到,它只保留了包含我想要的黄色颜色的区域。

图 8-21 遮罩掉图像中与球的黄色色调不同的颜色和区域。注意,球上有一些区域(亮反射/阴影区域)没有被拾取!
现在,相关的彩色物体已经被分离出来,接下来的步骤是识别出最大的颜色块。注意在图 8-21 中还有其他(虽然较小的)黄色区域吗?如果你没有正确编程,机器人可能会被这些区域混淆,朝它们而不是目标球移动。这可能会造成灾难——毕竟,你不希望它被远处的香蕉分散注意力!
假设遮罩中最大的部分是彩色球,下一步是实际找到这个最大区域。我们通过在遮罩中的每个检测到的物体周围绘制一个轮廓(类似轮廓线;参见图 8-22)来实现。我们可以通过一些基本的数学计算出每个轮廓的面积。然后,识别出最大区域,并假定它就是我们要找的目标球!

图 8-22 在遮罩中绘制的围绕最大单个物体的轮廓
完成此步骤后,我们只需编程让机器人朝向物体移动。如果目标在机器人的右侧,则向右移动。如果它在机器人的左侧,则向左移动。如果它在机器人的前方,则向前移动。
这就是用你的树莓派制作一个跟踪球的计算机视觉系统!现在是时候付诸实践了。
安装软件
你将需要几个 Python 库来启用计算机视觉。最重要的是,我们将使用 OpenCV,这是一个免费的开源实时计算机视觉编程函数库。你还需要 PiCamera Python 库来操作和处理树莓派相机模块,尽管在最新版本的 Raspbian 中默认已包含此库。
要安装 OpenCV Python 3 库的依赖项,请在终端中输入以下命令:
pi@raspberrypi:~ $ sudo apt-get install libblas-dev
libatlas-base-dev libjasper-dev libqtgui4 libqt4-test
注意
如果你在安装过程中遇到任何错误,或者安装似乎没有正确进行,请访问本书的网站nostarch.com/raspirobots查看任何更改并获得进一步指导。
当系统提示是否继续时,按 Y 然后按 ENTER。这条命令执行需要几分钟。
现在,你可以使用pip(我们之前使用过的 Python 软件管理工具)来为 Python 3 安装 OpenCV。输入以下命令:
pi@raspberrypi:~ $ sudo pip3 install opencv-python
OpenCV 安装完成后,使用以下命令检查是否已安装 PiCamera 库。它很可能会告知你已经安装了最新版本,但如果没有,请继续安装:
pi@raspberrypi:~ $ sudo apt-get install python3-picamera
这就是你所需要的全部!
识别你彩色球的 HSV 颜色
要识别特定颜色的球,你的树莓派机器人需要该颜色的 HSV 值。树莓派将使用这个值来比较每张图片的各个部分,以查看它是否是你希望机器人跟随的球的颜色。
你的球可能和我的颜色不同,因此你需要找出你球的确切 HSV 值。即使你和我一样有一个黄色的球,它的色调也可能与你的有所不同!
有多种方法可以识别你需要的色调值,但我发现最好的方法是尝试不同的值,看看效果如何。目的是找到一个与你特定颜色球匹配的值。为了帮助你完成这一点,我创建了一个测试程序hsv_tester.py,你可以在本书随附的软件包中找到它(https://nostarch.com/raspirobots/)。下一部分将带你通过运行该程序。
运行 HSV 测试程序
将你的机器人放置在一个光线良好的环境中,彩色球大约在它前方一米的位置。然后启动机器人上的树莓派,通过 VNC 远程查看其桌面。接着,在桌面上打开一个终端应用,找到hsv_tester.py程序,并使用以下命令运行它:
注意
我不会详细介绍这个测试程序是如何工作的,因为它与接下来几页中你将使用的实际球跟踪代码非常相似。我会在代码之后进行通常的详细解释。
pi@raspberrypi:~/robot $ python3 hsv_tester.py
你会看到一个提示,要求你输入 10 到 245 之间的色调值。试着估算你球的色调值;表 8-1 中的范围应该能大致告诉你从哪个光谱端开始。我的球是黄色的,所以我会猜测 40。输入这个值后,你将看到四个新窗口显示之前讨论的图像处理的不同阶段(参见图 8-23)。

图 8-23 HSV 测试程序的四个不同窗口
第一个窗口,标题为摄像头输出,是直接从摄像头模块➊获取的原始 RGB 视频输出。第二个窗口,标题为HSV,是将同一视频转换为 HSV 格式➋。接着,标题为颜色遮罩的窗口显示了与您提供的色调值匹配的图像部分➌。最后,标题为最终结果的窗口将颜色遮罩与原始视频流叠加,显示出隔离的区域➍。
如果最终结果窗口中的遮罩大致呈球形,你就找到了你的色调值!
你不太可能第一次就能准确得到色调值,就像我一样——色调没有匹配到我的球,而是匹配到画面中的订书机!若要重试,选择任何一个输出窗口(但不要选择终端窗口),然后按键盘上的 Q 键。这将冻结视频输出,你可以返回终端并输入另一个值进行尝试。
多尝试并调整色调值,直到你找到与你的彩色球完全匹配的色调。经过一段时间,我发现我的魔法数字是 28。找到你的值后,你应该能看到大部分球体而其他部分几乎不在画面中,就像我在图 8-24 中的样子。

图 8-24 我正确识别出我的色调值约为 28 时的输出窗口
记下这个值,因为你很快就需要它。在找到正确的数字后,通过在终端窗口按 CTRL-C 来关闭 HSV 测试程序。
编程让你的树莓派跟随一个球
在所有基础工作完成后,你现在可以编程让你的树莓派机器人跟随一个球!我们将使用的程序相对较长,并且比你目前遇到的任何程序都要复杂,所以我建议从软件包中下载它,而不是从这本书中复制,以减少输入错误。该程序名为ball_follower.py,你可以通过以下命令查看它:
pi@raspberrypi:~/robot $ nano ball_follower.py
这个程序有 75 行,因此在解释时我将它分成几个部分,并说明每个部分的工作原理。如果你更希望先运行代码并稍后理解它的工作方式,可以跳到第 193 页的下一节。
导入包并设置摄像头模块
首先,我们将导入所需的包并进行一些设置,如清单 8-1 所示。
➊ from picamera.array import PiRGBArray
from picamera import PiCamera
import cv2
import numpy as np
import gpiozero
➋ camera = PiCamera()
➌ image_width = 640
image_height = 480
➍ camera.resolution = (image_width, image_height)
camera.framerate = 32
rawCapture = PiRGBArray(camera, size=(image_width, image_height))
➎ center_image_x = image_width / 2
center_image_y = image_height / 2
➏ minimum_area = 250
maximum_area = 100000
清单 8-1 导入库并设置摄像头模块
程序的前几行➊导入了必要的库,包括 PiCamera 库的各个部分,这些部分使我们能够在 Python 中使用摄像头模块。我们还导入了 OpenCV 库cv2,像往常一样导入gpiozero,以及 NumPy 库np。NumPy 是一个用于科学计算的 Python 包,稍后在处理图像数据时会非常有用。
在 ➋ 处,我们初始化一个 PiCamera 对象,并将其分配给 camera 变量,在整个程序中使用。接下来,我们定义相机捕获的图像的大小 ➌ 和分辨率 ➍。我们不需要全高清视频帧,因为它们会降低速度和性能,所以我们将分辨率降到标准清晰度:640×480 像素。在接下来的几行中,我们指定了相机的帧率和原始捕获设置。
➎ 处的两行代码计算出图像的中心位置。稍后将使用这些信息来确定并比较球体在图像中的位置。
然后,在 ➏ 处,我们为彩色球设置了最小和最大面积。这可以防止你的机器人检测到小于 250 平方像素或大于 100,000 平方像素的任何彩色物体。这些是我发现效果相当不错的任意数字,但如果你想稍后更改它们,随时可以!
设置机器人和颜色值
本节内容涉及设置过程的最后部分,如 Listing 8-2 所示。
robot = gpiozero.Robot(left=(17,18), right=(27,22))
➊ forward_speed = 0.3
turn_speed = 0.2
➋ HUE_VAL = 28
➌ lower_color = np.array([HUE_VAL-10,100,100])
upper_color = np.array([HUE_VAL+10,255,255])
LISTING 8-2 设置机器人和颜色值
我们像之前一样设置机器人及其电机引脚,然后定义两个变量,分别用于前进速度和转向速度 ➊,值分别为 0.3 和 0.2。这将限制机器人朝向彩色球体时的移动速度。同样,这些是任意的数字,如果你发现更高或更低的值对你和你的机器人更有效,随时可以更改它们。
在 ➋ 处,我们设置了色调的数值。这是一个你必须更改的值,需要使用之前通过 HSV 测试程序找到的值。我将我的设置为 28。
接下来,我们设置了一个值的范围供机器人检查,而不是一个精确的数值 ➌。这样,环境的变化,比如房间的照明和亮度变化,仍会保持在这个小范围内,因此球体会继续被检测到。我们通过使用数组来创建 HSV 格式下颜色的上下限来实现这一点。
在编程中,数组是一个信息集合,其中每个数据项都有一个索引或位置与之相关联。数组可以根据需要长得无限大,可以存储你想要的任何东西,从人名到动物种类,再到数字列表。在 Python 中,数组中的第一个数据项的索引是 0,第二个数据项的索引是 1,第三个数据项的索引是 2,以此类推——换句话说,Python 从 0 开始计算数组中的项目。这意味着,在 Python 程序中,你可以请求数组中索引为 3 的数据项,它将返回在第四个位置的那项数据。
在这种情况下,我们使用数组表示 HSV 格式,因为每种 HSV 颜色都可以用三个数字来描述(色调、饱和度和亮度)。注意,我们实际上搜索的是色调±10 的范围,并且饱和度和亮度的范围是从 100 到 255。这确保机器人在每帧图像中会寻找更广泛的颜色范围,提高了它检测目标彩色球的概率。
这些数组可以通过我们导入的 NumPy 库使用。我们在这里使用 NumPy,因为它是一个经过高度优化的库,专门用于快速数组计算。这为我们提供了必要的速度,以便访问和分析每一帧中的每一个像素。
分析相机帧
程序的第三部分显示在 Listing 8-3 中。这是代码和计算机视觉过程的主要部分。
➊ for frame in camera.capture_continuous(rawCapture, format="bgr",
use_video_port=True):
➋ image = frame.array
➌ hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
➍ color_mask = cv2.inRange(hsv, lower_color, upper_color)
➎ image2, countours, hierarchy = cv2.findContours(color_mask,
cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
LISTING 8-3 开始捕获for循环,图像转换,和寻找轮廓
在➊处,我们启动了一个for循环,翻译成通俗的英语就是:“对于相机模块的每一帧,执行以下操作。”
接下来,当前帧的信息被保存到变量image中,作为一个数组 ➋。然后,图像的 RGB 数据通过 OpenCV 的cvtColor()函数转换为 HSV 格式 ➌。
一旦获取到 HSV 数据,就会创建色彩遮罩,该遮罩仅保留你希望的颜色,步骤为 ➍。我们使用 OpenCV 的inRange()函数,以便遮罩保留所有位于你选择的颜色上下限之间的颜色。
过程的下一阶段是为每个独立的物体在遮罩上绘制边框,这样就可以在后续对每个检测到的物体的区域进行比较。我们在➎步骤中使用 OpenCV 的findContours()函数来完成这一操作。
比较轮廓以找到你的球
接下来是 Listing 8-4,它比较每个轮廓并识别出最大的一个。
➊ object_area = 0
object_x = 0
object_y = 0
➋ for contour in contours:
➌ x, y, width, height = cv2.boundingRect(contour)
➍ found_area = width * height
➎ center_x = x + (width / 2)
center_y = y + (height / 2)
➏ if object_area < found_area:
object_area = found_area
object_x = center_x
object_y = center_y
➐ if object_area > 0:
ball_location = [object_area, object_x, object_y]
➑ else:
ball_location = None
LISTING 8-4 比较并找到最大轮廓
我们创建了三个变量➊,这些变量稍后将用来存储最大物体的面积和中心坐标。最初,我们将它们设置为零。
在➋处,我们开始了一个for循环,它会遍历每个检测到的轮廓。代码在➌处会为一个轮廓绘制一个矩形框来近似它的形状。这被称为边界框,它让物体处理起来更简单。我们将这个边界框的细节赋值给四个新变量:x、y、width和height。如你所料,width和height代表矩形的宽度和高度;x和y代表矩形左上角的 x 和 y 坐标。
接下来,我们使用矩形面积公式(宽度 × 高度 ➍)计算并存储当前轮廓的面积。然后我们计算并确定当前轮廓的中心坐标 ➎,让程序知道这个物体在帧中的位置。知道物体中心的坐标比知道它的左上角要有用得多。
在 ➏ 处,我们将当前轮廓的面积与之前找到的最大面积进行比较。如果当前轮廓的面积比之前的大,我们假设较大的面积很可能就是你的彩色球。因此,之前的轮廓信息会被丢弃,新的轮廓的详细信息会覆盖用于存储最大物体面积和中心坐标的三个变量。
一旦for循环 ➋ 完成,所有轮廓都被比较过,程序会验证是否找到了合适的轮廓,并通过if语句 ➐ 检查该轮廓的面积是否大于 0。如果是,说明找到了最大的轮廓,因此可能就是球,并将其详细信息保存在一个名为ball_location的列表(即一种基本数组)中。如果没有找到轮廓,ball_location变量将在else子句 ➑ 中被设置为None。
让你的机器人对球做出反应
程序的最后一部分,在 Listing 8-5 中,处理了让机器人根据在帧中检测到的彩色球的位置来移动。
➊ if ball_location:
➋ if (ball_location[0] > minimum_area) and (ball_location[0]
< maximum_area):
➌ if ball_location[1] > (center_image_x +
(image_width/3)):
robot.right(turn_speed)
print("Turning right")
➍ elif ball_location[1] < (center_image_x -
(image_width/3)):
robot.left(turn_speed)
print("Turning left")
➎ else:
robot.forward(forward_speed)
print("Forward")
➏ elif (ball_location[0] < minimum_area):
robot.left(turn_speed)
print("Target isn't large enough, searching")
➐ else:
robot.stop()
print("Target large enough, stopping")
➑ else:
robot.left(turn_speed)
print("Target not found, searching")
rawCapture.truncate(0)
LISTING 8-5 根据球的位置让机器人移动
这部分代码包含了许多if、elif和else语句,并且跳转较多,因此需要仔细阅读,特别注意缩进,以理解每个语句是如何构建的。
我们声明了一个简单的if语句 ➊,意思是“如果找到了球,就做这个”。如果没有找到球,程序会直接跳到else语句 ➑。程序随后会告诉用户没有找到合适的目标,并指示机器人左转,以便在周围环境中搜索球。
如果在当前帧中发现了一个球,if语句 ➋ 会检测球的大小(存储在ball_location列表的索引 0 处)是否在程序开始时定义的区域值范围内。如果检测到的物体太小,机器人会开始转动,看看是否能找到更大的目标 ➏。若检测到的物体太大(被else语句 ➐ 捕获),机器人不会再接近球并停止。
如果球在帧中,并且机器人确实需要移动,代码通过 ➏ 处理这一情况。在 ➌ 处,我们使用if语句来检测帧中球的 x 坐标是否大于中心点加上图像宽度的三分之一。如果是这种情况,球一定在帧的右侧,机器人因此向右移动。
位置 ➍ 的代码做的是相同的事情,但它会查看球在帧中的 x 坐标是否小于中心点加上图像宽度的三分之一。在这种情况下,机器人会向左转。
最后,如果球不在图像的左侧或右侧,它一定在你机器人前面,因此机器人会被指示向前移动➎。
如图 8-25 所示,这段代码基本上将摄像头帧分成了三个不同的区域:左侧、右侧和前方。我们使用整个帧宽度的三分之一作为中心点两侧的中间部分。也就是说,中间部分代表了每帧的三分之二。如果球出现在这里,机器人就会向前移动。如果球出现在任一侧,机器人就会向左或向右移动。左侧和右侧区域分别是每帧的六分之一。
这就是跟随球体程序的全部内容!刚开始看起来代码可能有些复杂,但和计算机科学中的大多数事情一样,如果你分解开并仔细观察,你会发现它由之前用过的简单概念构成。

图 8-25 一张显示如何将帧分割为三个区域以便进行移动的示意图
运行程序:让你的机器人跟随一个彩色球!
现在你可以进入这个项目的激动人心的部分了:让你的机器人真正开始跟随你的彩色球。给机器人安装电池,并将其放置在地面或其他大型平坦的表面上。同时将彩色球放置在这个环境中的某个地方,如图 8-26 所示。

图 8-26 我的机器人,准备去追寻我的黄色球!
当一切设置好后,使用以下命令运行程序:
pi@raspberrypi:~/robot $ python3 ball_follower.py
你的机器人应该会活跃起来,开始追踪你的彩色球。和你新智能的宠物玩一场取球游戏吧!
和往常一样,按 CTRL-C 停止程序。
实验图像处理
就像上一章中的跟随线项目一样,计算机视觉和图像处理是计算机科学和机器人领域的两个方向,这些领域往往需要精细调节,以改善结果和能力。这里有一些建议,供你进行实验。
颜色与物体
虽然你的彩色球是机器人一个很好的起始目标,但你可以轻松地将其扩展。例如,为什么不通过扫描每一帧来引入第二种颜色,寻找一组次要的 HSV 值呢?让你的机器人跟随黄色和红色物体,比如说。记得你可以回到 HSV 测试程序,找出其他颜色的色调和颜色代码!
你不仅仅局限于球体。你可以让你的机器人跟随或寻找任何主要是单一颜色的物体。尝试用你周围的其他物品做实验吧!
速度
机器人移动的速度对图像处理的质量有很大的影响:通常来说,速度越快,错过目标颜色物体的可能性越大。话虽如此,欢迎你尝试调整在追踪球程序开始时定义的速度值——你可能会调试并改善机器人的表现!
目标物体的最小/最大面积
试验目标物体的最小和最大面积。记住,默认情况下,你的机器人不会朝小于 250 平方像素的物体移动,而且会停在大于 100,000 平方像素的物体前。
通过更改这些数值,你可以让机器人朝着可能较小的目标移动,甚至在离目标更近时停下。一个有趣的想法是增加最大面积,直到机器人在接近你的彩色球时不会停下。结果就是,机器人通常会撞上球并“踢”它……然后再跟着它滚动,重复这个过程!
记住,你的摄像头模块每一帧视频的分辨率是 640×480 像素,因此 307,200 是可能的最大平方像素数。
避免行为
目前,机器人喜欢你的彩色球,但如果你改变它的行为,让它害怕彩色球会怎么样呢?尝试编辑程序,让机器人跑开,而不是朝球移动。
这一部分的扩展可以让你的机器人朝某些颜色的球移动,而避免其他颜色的球。例如,它可以喜欢红色的球,但对黄色的球感到害怕!
总结
在本章中,你赋予了机器人寻找到、识别并追踪彩色球的高级能力。你已经学习了图像处理的基础,并使用官方的树莓派摄像头模块在 Python 中实现了整个计算机视觉过程。
至此,你已经完成了本书的项目部分!你的小机器人现在已经长大,而你就是它骄傲的父母。不过,这并不是终点;请查看第 195 页的“下一步”部分,获取继续进行机器人、编程和树莓派冒险的指导和建议。
第九章:下一步
现在你已经读完了本书,是时候走向这个世界,制作属于你自己的机器人和其他树莓派项目了!我希望你已经学会并掌握了帮助你在未来计算机科学冒险中所需要的技能。
但是要知道,你并不孤单!无论在线还是离线,都有无数资源可以帮助你在下一步中走得更远。以下是一些建议。
树莓派大叔
我运营着受欢迎的树莓派 YouTube 频道 The Raspberry Pi Guy,在这里我提供免费的教程和教育视频。我有许多关于树莓派的各类视频,从基础机器人技术到 DIY 电动滑板,所有内容都以简明易懂且易于跟随的方式呈现(见图 A-1)。

图 A-1 The Raspberry Pi Guy YouTube 频道
你可以通过以下链接查看内容,如果喜欢看到的内容,别忘了订阅。
The Raspberry Pi Guy YouTube 频道 (www.youtube.com/TheRaspberryPiGuy/)
Raspberry Pi Guy 网站 (www.theraspberrypiguy.com/)
联系我们!
如果你喜欢这本书并希望联系我或分享你的进展,我非常乐意通过 Twitter 听到你的声音。你可以关注并给我发推 @RaspberryPiGuy1。我一定会看到你的推文并回复,尤其是如果你使用了标签 #raspirobots。
其他网站
树莓派和机器人领域都拥有庞大、开放且极具包容性的在线社区,你可以在这些社区中阅读和贡献。以下是一些你可以从中学习并获得灵感的网站:
官方树莓派基金会网站 (www.raspberrypi.org/) 这是你在书籍开始时用来下载树莓派操作系统的站点。基金会的网站提供了丰富的教育资源和适用于各个层次和能力的项目。你还会找到树莓派论坛,在这里你可以注册一个账户,与其他有相似兴趣、问题和疑问的人互动;如果你在未来的项目中遇到困难,这里是寻求帮助的完美地方。甚至有一个专门的“自动化、传感与机器人”版块!该网站还包括一个定期更新的博客,内容涵盖社区的最新新闻。
Adafruit 学习系统 (learn.adafruit.com/) 这是一个来自 Adafruit 电子社区的资源和在线课程集合。在这里,你会找到涵盖各种硬件和软件的详细教程,所有内容都有开源代码和帮助。如果你需要灵感来启动下一个项目,这是一个不错的地方!
官方 Python 网站 (www.python.org/) 本书已经为你提供了一个关于编程和 Python 编程语言的精彩介绍,如果你想继续提升你的编程技能,可以看看官方 Python 网站。你将在那里找到所有你可能希望拥有的文档和指南!在未来,你可能还会希望探索其他编程语言,如 C++ 或 Java,这时只需要在 Google 上搜索教程——几乎可以找到成千上万的资源!
新阿特拉斯机器人新闻 (newatlas.com/robotics/) 如果你对最新的机器人技术新闻和该领域的进展感兴趣,可以查看新阿特拉斯网站的机器人栏目。新阿特拉斯是一个报道技术新闻的在线出版物,你将会发现一些令人惊叹的内容,这些内容可能会激励你做出一些了不起的事情,并进一步推动机器人领域的发展!
俱乐部和活动
在网上你可以做很多事情来学习机器人技术和 Raspberry Pi,但没有什么能替代面对面的俱乐部、活动和聚会。幸运的是,在计算机科学领域你会找到很多这样的机会。以下是一些建议,不过你的所在位置会影响你能参加的活动,所以一定要了解你所在地区是否有相关的俱乐部和活动!
Raspberry Jam (www.raspberrypi.org/jam/) Raspberry Jam 是由社区自主组织的活动,旨在让所有年龄段的人们围绕 Raspberry Pi 进行交流、学习和分享项目。Raspberry Jam 在全球各地举办,由各种各样的人组织。活动通常包括面向初学者的工作坊、展示与讲座,并由社区成员主讲。无论你是初学者还是专业人士,来自各个背景和技能层次的人都欢迎参加这些活动。你可以使用网站上的 Find a Jam Near You 工具找到你所在地区的活动。如果你来参加位于英国剑桥的某个 Jam 活动,或者参加位于英国爱丁堡的活动,很可能会碰到我——记得打个招呼!
Pi Wars (piwars.org/) Pi Wars 是一项基于挑战的机器人竞赛,参赛机器人由 Raspberry Pi 控制。无论是专业团队还是业余团队,都可以打造机器人并参加比赛,任务包括障碍赛、速度测试和迷宫解谜等非破坏性挑战。比赛通常在一个周末举办,并且在英国剑桥举行。你可以作为参赛者或观众参加活动;详情请参阅网站获取更多信息。
编程俱乐部 (www.codeclubworld.org/) 和 Coder Dojo (coderdojo.com/) 编程俱乐部和 Coder Dojo 是全球范围内由志愿者领导的、为年轻人提供的免费编程俱乐部网络。程序员和其他人聚集在一起,帮助年轻一代学习如何编程并发展他们的计算机科学技能。你可以通过访问各自网站上的工具,查看是否有适合你的俱乐部。
书籍和出版物
如果你从本书中享受到了学习计算机科学和 Raspberry Pi 的乐趣,你可能希望通过另一本书或出版物继续这段旅程。以下是一些建议:
Python 速成课程,作者:Eric Matthes(No Starch Press,2015 年)
20 个简单的 Raspberry Pi 项目,作者:Rui Santos 和 Sara Santos(No Starch Press,2018 年)
Raspberry Pi 用户指南,作者:Eben Upton 和 Gareth Halfacree(Wiley,2016 年)
The MagPi (https://www.raspberrypi.org/magpi/),由基金会出版的免费阅读、每月一期的 Raspberry Pi 杂志,包含项目、编程和其他文章
第十章:树莓派 GPIO 引脚图
这里你可以找到一张完整标注的树莓派 GPIO 引脚图。每个引脚都标注了其物理编号和 BCM 编号。
物理编号仅仅对应于引脚的实际物理位置,从 1 开始,一直到 40。每个引脚上的 BCM 编号(例如 BCM 25)被称为 Broadcom 引脚编号或 GPIO 编号。这些编号由树莓派的处理器内部使用,你通常需要在 GPIO Zero 和其他编程库中使用它们。
一些引脚有附加的功能,功能名称在括号中标出;如果你想了解更多关于这些功能的信息,请参阅树莓派官网的官方文档(https://www.raspberrypi.org/documentation/usage/gpio**/)。

图 B-1 树莓派 GPIO 引脚
第十一章:电阻器指南
电阻器是专门设计用于在电路中增加阻抗的组件,以减少通过电路的电流。在本书中,你将在多个部分使用它们,执行各种任务,从确保 LED 的安全电流到创建电压分压电路。
电阻器的准确阻值是以欧姆(Ω)为单位测量的。如果你还不知道电阻器的阻值,可以通过其颜色带来确定。下表显示了每种颜色对应的值。
注意
如果你像我一样是色盲,通过电阻器的颜色带来确定其值几乎是不可能的。我建议将电阻器放入有组织并标记的袋子中,这样你可以快速而轻松地识别它们的值。如果你遇到一个不明电阻器,可以使用万用表的电阻档来帮助你。只需将万用表的两个探头连接到电阻器的两端,它将显示其精确的阻值。
| 颜色 | 第一带 | 第二带 | 第三带 | 倍数 | 容差 |
|---|---|---|---|---|---|
| 黑色 | 0 | 0 | 0 | 1 Ω | |
| 棕色 | 1 | 1 | 1 | 10 Ω | +/–1% |
| 红色 | 2 | 2 | 2 | 100 Ω | +/–2% |
| 橙色 | 3 | 3 | 3 | 1 KΩ | |
| 黄色 | 4 | 4 | 4 | 10 KΩ | |
| 绿色 | 5 | 5 | 5 | 100 KΩ | +/–0.5% |
| 蓝色 | 6 | 6 | 6 | 1 MΩ | +/–0.25% |
| 紫色 | 7 | 7 | 7 | 10 MΩ | +/–0.10% |
| 灰色 | 8 | 8 | 8 | +/–0.05% | |
| 白色 | 9 | 9 | 9 | ||
| 金色 | 0.1 Ω | +/–5% | |||
| 银色 | 0.01 Ω | +/–10% |
标准电阻器有四个颜色带。前两带表示电阻器值的前两位数字。第三带是倍数,表示在前两位数字后的零的数量。第四带是电阻的容差;除非你在进行特殊和精确的工作,否则通常不需要担心最后一带。
例如,我们来计算图 C-1 中所示电阻器的阻值。

图 C-1 四带电阻器
第一带是绿色,因此它的值是 5。第二带是蓝色,因此它的值是 6。第三带是黄色,表示四个零。第四带是金色,意味着容差为+/–5%。
因此,该电阻器的阻值为 56 × 10,000 = 56,000 Ω,或 56 kΩ。
就是这样,通过颜色带来计算电阻器的阻值!
第十二章:如何进行焊接
焊接是将电子元件永久性地焊接在一起的过程。它涉及将一种称为 焊锡 的填充金属合金在两个或多个组件之间熔化(见 图 D-1)。
这一过程不仅将部件物理地连接在一起,还在电气上将它们连接。与使用面包板不同,焊接是永久性的。在你从事机器人技术、电子学和树莓派的过程中,你会遇到需要焊接的组件(例如,将电线焊接到电机端子上),所以这是你必须学习和练习的关键技能。

图 D-1 将电线焊接到电机端子——机器人技术中的常见任务
你需要的工具
为了将元件焊接在一起,你需要一些工具和材料:
-
焊接铁
-
焊锡
-
焊接铁架和焊接头清洁器
这些工具通常可以从常见的在线零售商和本地五金店购买。让我们仔细看看每个部分。
焊锡
首先,你需要熔化的填充金属来制作焊接接头。如图 D-2 所示,焊锡是一种低熔点金属合金,通常熔点在 180 到 200 摄氏度(356–392 华氏度)之间。
过去,由于铅具有较低的熔点和出色的电气性能,铅曾被用作焊锡材料。然而,现在我们知道铅是一种重金属,对人类有毒。因此,无铅焊锡(主要由锡和铜组成)成为现代行业标准,我建议你购买这种焊锡。如果你在线购买,只需搜索“无铅焊锡”。它通常以直径在 0.5 到 0.8 毫米之间的线材形式提供。

图 D-2 无铅焊锡
焊接铁
焊接铁,如图 D-3 所示,是加热焊锡到其熔点的工具。

图 D-3 我可靠的 Tenma 焊接铁
焊接铁有各种价位,通常最低从 $10 起,最高超过 $100!作为初学者,你可能不需要购买带有专业功能的昂贵焊接铁。你所需要的是一把性能可靠、不会给你带来压力的普通焊接铁。
一款常见的入门焊接铁是 Antex XS25,售价大约为 $30。它是一款快速加热、固定温度的高质量工具,能为你使用多年。请注意,对于你大概率会进行的精细电子焊接,焊接铁的焊接头应该选择细尖型。大多数焊接铁都配有这种预安装的焊接头,而像 XS25 这样的焊接铁具有便于更换的焊接头。
我个人使用的是 Tenma 60W 可调温度焊接站,售价大约为 $60。
焊接铁架和焊接头清洁器
焊接铁的温度会升高到超过 200 摄氏度,因此非常重要的是只触摸焊接铁的把手。我建议使用一个焊接铁架,它可以在焊接接头之间安全地存放和固定你的焊接铁,避免烫伤你、电子设备或桌面表面(见图 D-4)!

图 D-4 焊接架和海绵
通常焊接架会配有内建的焊接头清洁器。这个清洁器用于在连接之间清洁焊接铁,使其保持最佳工作状态。最常见的两种清洁器是湿海绵或一种含有黄铜屑的磨蚀性容器,见图 D-4 和图 D-5。我推荐使用黄铜屑,它能更彻底地清洁焊接头。

图 D-5 焊接头清洁器
可选配件
目前为止提到的工具和材料是焊接的基本必需品,但还有一些额外的小物件可以让你的工作更轻松!
例如,你可能需要去除焊点上的焊锡。你可以使用一些去焊带(也叫吸锡带)或者吸锡器来实现,如图所示。我在本指南中不会讲解去焊技巧,如果你想提高焊接技巧,可以在线搜索相关信息和视频。

如果你在焊接时发现焊锡流动不顺畅,液体助焊剂笔会有所帮助。通过涂抹一种叫做液体助焊剂的特殊溶液,助焊剂笔帮助焊锡更好地附着在焊点上。
你可能会发现,在焊接时定位和固定电子组件变得困难。此时,像这里展示的帮手之手工具套件可能会很有用。

许多你需要焊接的组件非常小,这对于视力不太完美的人来说可能是一个问题。如果你有这种情况,你可能会发现放大镜(通常与辅助工具“帮手之手”结合使用)是必不可少的工具。
焊接组件
现在我们来演示如何将两个组件焊接在一起。我将通过焊接电线到电动机端子来演示,这也是你在第三章中可能需要做的操作。
准备焊接
在打开焊接铁之前,首先要准备好工作区域。焊接区域需要:
通风良好的区域 选择一个通风良好的地方,因为焊接会产生烟雾,尽量避免吸入这些烟雾。
合适的工作台面 由于焊接铁非常热,请确保工作台面是耐热的,或者在焊接区域放置一些废料材料。比如一块纸板、一块切割垫或一块旧木板都可以。
眼部保护 在焊接过程中,焊锡和助焊剂可能会飞溅出来。我建议佩戴安全眼镜或护目镜来保护眼睛。
一切准备好后,将焊接铁放在支架上,然后插入电源插座。等待焊接铁加热;如果你的焊接铁是高端型号,可能几秒钟就热了;如果是像 Antex XS25 这种入门型号,可能需要几分钟。最重要的是,记住在插电时不要触摸焊接铁的铁尖。即使你拔掉了电源,也不要触摸铁尖!它会需要一段时间才能冷却下来。
一旦插上焊接铁,切勿让设备无人看管。如果你需要离开房间,拔掉焊接铁的插头,并在离开前等它完全冷却。没有任何风险是值得冒的。
焊接铁尖的镀锡
在开始焊接接头之前,务必镀锡你的焊接铁尖。镀锡是将焊接铁尖涂上一层焊锡的过程。这会使实际焊接变得更容易,并帮助焊锡的流动更加顺畅。
首先,当焊接铁加热后,通过用湿海绵擦拭铁尖或将其插入黄铜屑中来清洁焊接铁。
之后,放一些焊锡到焊接铁尖上,焊锡应该会在接触时融化。现在,将焊接铁尖的下四分之一涂上一层焊锡。使用焊接铁尖清洁器清理掉多余的焊锡,并重复这个过程,直到你的焊接铁尖光亮并且涂满焊锡,就像我在图 D-6 中的样子。

图 D-6 给我的焊接铁尖镀锡
如果你正在焊接许多组件,应当在合适的时候重新给焊接铁尖镀锡,尤其是当它不再光亮时。
组件的准备
始终要确保你先准备好待焊接的组件。将零件放在工作台上,并按照你打算焊接的方式将它们定位。为了将电线焊接到电机端子上,你需要将电线穿过端子,就像图 D-7 中所示的那样。在这之前,确保你剥皮了电线的一端,即去掉大约四分之一英寸的塑料外层,露出导电金属芯。你应该使用剥线钳来完成这项工作。

图 D-7 一根准备焊接到我的电机端子的电线
对于其他组件,你可能希望使用前面提到的“助焊手”夹具将它们固定住。
焊接完美的接头
现在一切准备就绪,开始焊接吧!从焊锡线卷上拉出大约 6 英寸的焊锡,并用手握住焊接铁的把手。它应该握在你的主手里,就像握着一支笔或铅笔一样。确保你握住焊锡线时,至少离焊锡的末端有几英寸,以免烫伤自己。
焊接点好坏的关键是不要将焊接铁直接接触到焊锡并让它融化到组件上。相反,应将加热后的焊接铁接触到你打算焊接的组件上,保持 2 到 3 秒钟,使组件本身被加热。然后,直接将焊锡加到加热过的组件上。
焊锡会流向组件的最热部分,因此,如果你没有预热你要焊接的部件,可能会发现焊锡流到焊接铁上,形成一个凌乱的球状物。如果发生这种情况,别担心:只需要清洁焊接铁,再重新开始操作。
因此,要焊接一个完美的焊点,就像图 D-8 中的那样,按照以下步骤操作:
警告
不要立刻触碰刚刚焊接的组件,因为它们会非常烫!
-
将已经镀锡的焊接铁尖端接触到你要焊接的组件上,并保持 2 到 3 秒钟。
-
在焊接铁仍然接触组件时,将焊锡线的末端送入焊点;它应在接触时融化并流入焊点。
-
当你融化了足够的焊锡并填满整个焊点时,移开焊锡,但保持焊接铁继续接触焊点再保持一秒钟。这可以让焊锡流动并稳定下来。
-
将焊接铁从焊点移开,清洁焊接铁尖端上的多余焊锡,然后将其放回支架中。

图 D-8 我焊接好的电机端子——注意焊点的光亮和平滑的锥形外观
一个好的焊接点应该是平滑且光亮的,形状像一个小锥体,有点像一个小火山。例如,将电线焊接到电机端子上,与将针脚焊接到印刷电路板上的方式略有不同,因此可以参考图 D-9 来了解一个良好的 PCB 焊接连接的样子。

图 D-9 树莓派底部的 PCB 焊接点(虽然这些是由自动化机器完成的,但它们仍然是一个很好的学习范例)
如果你的焊接点不正确,别慌!拿起焊接铁,把尖端重新放回焊点加热它。看看焊锡是否流动并更好地稳定,如果没有,就加一些焊锡以确保焊接点正确。
图 D-10 展示了一些常见的焊接错误及其解决方法。

图 D-10 常见的焊接错误及其解决方法
总结
焊接技巧是一个重要的制作技能,只要多加练习,它会带给你很大的帮助!按照这里的指导,或者上网观看一些示范视频来完善你的技巧。
第十三章:启动时运行程序
在本书中,我已经向你展示了如何使用简单的终端命令运行你的机器人程序。虽然这种方法非常适合原型开发,但未来你可能希望在每次打开机器人时都自动运行一个程序,而无需远程访问。你可以通过编辑 rc.local 配置文件轻松实现这一点。
当你启动树莓派时,它会经过一个引导过程。引导过程结束后,树莓派会查找rc.local文件中是否有需要执行的最后命令或代码。通过添加自定义的 Python 命令,你可以让本书中的任何程序在启动时自动运行。方法如下!
编辑 rc.local 文件
首先,确保你希望在启动时运行的程序是完整的,并且按你想要的方式运行。在终端中完成编程、编辑和调试过程要比等待程序在启动时运行要好得多。这种方法可以避免你一直开关树莓派。
然后,在终端中的任何位置,使用 Nano 文本编辑器打开rc.local文件,如下所示:
pi@raspberrypi:~ $ sudo nano /etc/rc.local
确保在开始时加上sudo。这个命令允许你以 root 用户权限进行编辑,这样你对文件所做的更改才能保存,否则它们会消失!
输入上述命令后,你将看到一个类似于 Listing E-1 的文件。
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the
# execution bits.
#
# By default this script does nothing.
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
➊
exit 0
LISTING E-1 rc.local 文件的内容
现在,使用箭头键滚动到fi和exit 0之间的空间 ➊。在这里你可以添加任何希望树莓派在启动时执行的命令。不管你添加什么,你必须保持exit 0在文件底部不被修改。
如果你想在启动时运行一个 Python 3 程序,在➊处插入如下命令:
python3 /your/file/path/here/filename.py &
用指向正确目录和程序的有效文件路径替换该路径。同时,确保在命令的末尾加上(&)符号,以确保你的程序不会阻止树莓派继续引导。
添加你希望在启动时执行的程序后,保存你的工作并通过按下 CTRL-X 并按照提示退出 Nano 文本编辑器。
实践示例
假设你希望在每次打开机器人时都运行ball_follower.py程序。为此,在树莓派上打开rc.local文件,并在exit 0语句之前插入以下行:
python3 /home/pi/robot/ball_follower.py &
现在,文件的最后部分应该如下所示:
--snip--
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
python3 /home/pi/raspirobots/ball_follower.py &
exit 0
让我们测试一下,看看是否有效。保存文件,然后按照如下步骤重新启动树莓派:
pi@raspberrypi:~ $ sudo reboot
如果成功,您的机器人将执行ball_follower.py代码。如果没有成功,可以通过 SSH 远程访问树莓派,再次编辑rc.local文件。确保你有正确的完整文件路径,并且没有任何拼写错误。
这就是让程序在启动时运行的全部内容!
更新
访问 nostarch.com/raspirobots/ 获取更新、勘误和其他信息。
来自
NO STARCH PRESS的更多无废话书籍

ARDUINO 项目手册,第 1 卷
25 个实用项目帮助你入门
你开始了
作者 MARK GEDDES
2016 年 6 月,272 页,$24.95
ISBN 978-1-59327-690-4
全彩

初学者电路指南
九个简单项目与
灯光、声音以及更多!
作者 ØYVIND NYDAL DAHL
2018 年 10 月,80 页,$17.95
ISBN 978-1-59327-904-2
全彩

20 个简单的树莓派项目
玩具、工具、小工具及更多!
作者 RUI SANTOS 和 SARA SANTOS
2018 年 4 月,288 页,$24.95
ISBN 978-1-59327-843-4
全彩

树莓派家庭破解
12 个间谍项目,监视你的
家庭,修改 Minecraft,破解
无线信号等更多!
作者 DAN ALDRED
2019 年春季,134 页,$24.95
ISBN 978-1-59327-946-2
全彩

10 个为极客设计的 LED 项目
构建光效服装,科幻
小工具和其他巧妙的发明
编辑 JOHN BAICHTAL
2018 年 7 月,240 页,$24.95
ISBN 978-1-59327-825-0
全彩

PYTHON FLASH CARDS
语法、概念和示例
作者 ERIC MATTHES
2019 年冬季,101 张卡片,$27.95
ISBN 978-1-59327-896-0
全彩
电话:
1.800.420.7240 或
1.415.863.9900
电子邮件:
SALES@NOSTARCH.COM
网页:
适合 10 岁以上
“机器人学的轻松入门”
EBEN UPTON,树莓派公司首席执行官(贸易)有限公司
无需经验!
学习机器人技术与树莓派 将带你从一个新手制造者快速成长为机器人构建者。你将首先构建一个由树莓派微型计算机驱动的双轮机器人,然后使用世界上最流行的编程语言 Python 对其进行编程。逐步地,你将通过添加越来越复杂的功能来改善你的机器人,直到它能够跟随线路、避开障碍,甚至识别一定大小和颜色的物体。
学习如何:
使用 Wii 遥控器远程控制你的机器人
教你的机器人使用传感器避开障碍物
编程让你的机器人自主跟随线路
自定义你的机器人,添加 LED 和扬声器,让它发光并播放声音
用 Pi 摄像头查看你的机器人所见
在阅读本书的过程中,你将学习基本的电子技能,例如如何连接各个部件,使用电阻器和调节器,并确定你的机器人需要多少电力。你还将学习 Python 编程的基础,并通过与伺服电机、马达和传感器等硬件的实际操作,获得足够的经验,从而将你的创作扩展到简单机器人之外。
Matt Timmons-Brown 运营着世界上最受欢迎的 Raspberry Pi YouTube 频道“The Raspberry Pi Guy” (www.youtube.com/theraspberrypiguy),该频道的观看次数已经超过 500 万。他是爱丁堡大学的计算机科学学生,来自英国剑桥。
需要 Raspberry Pi 和 Python 3

极客娱乐的至高之作™



















浙公网安备 33010602011771号