有一天,无人驾驶汽车将主宰我们的街道和高速公路。虽然感觉信息和控制算法将位于汽车本身,但我们将有能力(这可能是一项立法要求)从其他地方控制汽车。控制无人驾驶汽车需要将汽车的感官信息以速度、GPS 位置等形式发送到控制站。相反,来自控制站的信息将以交通和方向的形式发送给汽车。
在本章中,我们将探讨 T.A.R.A.S.发送感官信息和 T.A.R.A.S.接收控制信息。
本章将介绍以下主题:
要完成本章,您应该拥有一辆完整的 T.a.R.a.S 机器人车,如第 13 章、介绍覆盆子 Pi 机器人车中所述。与本书的其他章节一样,需要掌握 Python 的实用知识,以及对面向对象编程的基本理解。
本章中的项目将涉及通过互联网与 T.A.R.A.S.沟通。在我们在控制 T.a.R.a.S.的仪表板上创建开关之前,我们将更深入地了解我们在第 15 章中创建的仪表板模拟拨号盘,将机器人车的感官输入连接到网络。这些项目大约需要 2 小时才能完成
为完成本项目,需要以下各项:
在第 15 章中将机器人车的感知输入连接到网络中,我们能够通过网站将距离感知数据发送到云 https://thingsboard.io/ 。我们以显示距离值的模拟仪表结束。在本节中,我们将通过定制模拟小部件来深入了解它。
这就是我们改变测距仪外观的方式:
登录你的 ThingsBoard 帐户
单击仪表板
点击 ROBOTEYES 标题
单击屏幕右下角的橙色铅笔图标
您会注意到距离模拟拨号盘已更改(请参见以下屏幕截图)
首先,在拨号盘的右上角有三个新图标
在右下角,颜色也变为浅灰色
您可以通过将鼠标悬停在右下角来调整小部件的大小
您还可以在仪表板上移动小部件
右上角的 X 允许您从仪表板中删除此小部件
带下划线箭头的图标允许您将小部件作为.json
文件下载。此文件可用于将小部件导入 ThingsBoard 上的另一个仪表板
单击小部件上的铅笔图标可生成从右侧滑出的菜单:
RobotEyes
:rgb(50,87,126)
看看距离模拟仪表,很明显,负数对我们的应用没有多大意义。让我们把范围定为0
到100
:
单击小部件上的铅笔图标
单击高级选项卡
将最小值更改为0
,将最大值更改为100
:
0
到100
:最后一个技巧是,我们将在账户外显示仪表板(我们在第 10 章、发布到 Web 服务中也这样做了)。这也允许我们将仪表板发送给朋友。那么,我们为什么要在帐户之外查看仪表板呢?物联网的核心理念是,我们可以从一个地方获取信息,并将其展示在其他地方,也许是世界的另一边。通过使我们的仪表板在我们的帐户之外可访问,我们允许在任何地方设置仪表板,而无需共享我们的帐户信息。想象一下世界上某个地方的一个大电脑屏幕,屏幕的一小部分显示了我们的仪表板。显示来自 T.A.R.A.S.的距离信息可能不是很多人感兴趣的,但概念才是重要的。
要共享我们的仪表板,请执行以下操作:
能够在仪表板上看到感官数据令人印象深刻。但是,如果我们想从仪表板中实际控制某些东西,该怎么办?在本节中,我们将这样做。我们将首先构造一个简单的开关来控制 T.a.R.a.S.上的 LED。然后我们将对此进行扩展,让 T.A.R.A.S 通过互联网上的一个按钮来跳舞。
让我们首先将仪表板的名称从RobotEyes
更改为RobotControl
:
RobotEyes
改为RobotControl
:现在,让我们从 ThingsBoard 仪表板控制 T.A.R.A.s 上的 LED。
为了控制 LED,我们需要创建一个开关:
Green Tail Light
并点击显示标题toggleGreenTailLight
:那么,我们刚才在这里做了什么?我们在仪表板上添加了一个开关,该开关将发布一个名为toggleGreenTailLight
的方法,该方法将返回一个true
或false
的值(默认返回值为this is a switch
现在我们有了开关,让我们在 Raspberry Pi 上编写一些代码来响应它。
为了控制 T.A.R.A.S 上的绿色 LED,我们需要为 T.A.R.A.S 上的 Raspberry Pi 编写一些代码。我们需要仪表板的访问令牌(参见第 15 章将机器人车的感官输入连接到网络,了解如何获取该令牌):
import paho.mqtt.client as mqtt
from gpiozero import LED
import json
THINGSBOARD_HOST = 'demo.thingsboard.io'
ACCESS_TOKEN = '<<access token>>'
green_led=LED(21)
def on_connect(client, userdata, rc, *extra_params):
print('Connected with result code ' + str(rc))
client.subscribe('v1/devices/me/rpc/request/+')
def on_message(client, userdata, msg):
data = json.loads(msg.payload.decode("utf-8"))
if data['method'] == 'toggleGreenTailLight':
if data['params']:
green_led.on()
else:
green_led.off()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set(ACCESS_TOKEN)
client.connect(THINGSBOARD_HOST, 1883, 60)
client.loop_forever()
control-green-led-mqtt.py
那么,我们刚才在这里做了什么?使用 ThingsBoard 网站上的样板代码,我们构建了一个消息查询遥测传输(MQTT客户端,该客户端监听仪表板并在收到toggleGreenTailLight
方法时做出响应。我们通过在on_connect
方法中订阅'v1/devices/me/rpc/request/+'
来实现这一点。我们在第 10 章中使用了 MQTT,发布到 Web 服务中也使用了 MQTT。然而,由于这段代码几乎只是 MQTT 代码,所以让我们更仔细地研究一下。
MQTT is a lightweight messaging protocol based on a publisher
and subscriber
method, perfect for use in the Internet of Things. A good way to understand publishers and subscribers is to relate them to newspapers of the past. The publisher was the entity that produced the newspaper; the subscribers were the people that bought and read the newspaper. The publisher did not know, or even have to know, how many subscribers it had in order to print the newspaper (not taking the cost of publishing into account). Think of the giant newspapers that published every day, not knowing how many people would buy their newspaper. So, the publisher can have many subscribers and, conversely, the subscriber can subscribe to many publishers, as a reader could read many different newspapers.
我们首先导入代码所需的库:
import paho.mqtt.client as mqtt
from gpiozero import LED
import json
THINGSBOARD_HOST = 'demo.thingsboard.io'
ACCESS_TOKEN = '<<access token>>'
green_led=LED(21)
这里需要注意的是json
和pho.mqtt.client
库,它们是与 MQTT 服务器通信所需的。THINGSBOARD_HOST
和ACCESS_TOKEN
是连接到正确的服务器和服务所需的标准变量。当然,还有GPIO Zero LED
类,它将green_led
变量设置为 GPIO 引脚21
(恰好是 T.A.R.A.S 上的绿色尾灯)。
on_connect
方法打印出连接信息,然后从 ThingsBoard 仪表板订阅将我们连接到rpc
方法的服务:
def on_connect(client, userdata, rc, *extra_params):
print('Connected with result code ' + str(rc))
client.subscribe('v1/devices/me/rpc/request/+')
正是on_message
方法允许我们真正修改代码以达到我们的目的:
def on_message(client, userdata, msg):
data = json.loads(msg.payload.decode("utf-8"))
if data['method'] == 'toggleGreenTailLight':
if data['params']:
green_led.on()
else:
green_led.off()
我们首先从我们的msg
变量中收集data
并使用json.loads
方法将其转换为json
文件。method
声明on_message(client, userdata, msg)
也是 ThingsBoard 网站上的标准样板代码。我们真正关心的只是得到msg
值。
第一个if
语句if data['method'] == 'toggleGreenTailLight'
检查我们的msg
是否使用了我们在 ThingsBoard 仪表板上的开关设置的toggleGreenTailLight
方法。一旦我们知道msg
包含此方法,我们提取data
中的另一个键值对,使用if data['params']
检查True
值。因此,换句话说,我们返回调用on_message
方法的json
文件将类似于{'params': True, 'method': 'toggleGreenTailLight'}
。这基本上是一个包含两个键值对的 Python 字典。这似乎令人困惑,但最简单的思考方式是将其想象为一个方法(json
版本(toggleGreenTailLight
)和一个返回值(True
)。
真正理解发生了什么的一种方法是在on_message
方法的print data
内部,在data = json.loads(msg.payload.decode("utf-8"))
之后放一个print
语句。因此,该方法类似于以下内容:
def on_message(client, userdata, msg):
data = json.loads(msg.payload.decode("utf-8"))
print(data)
.
.
.
当params
返回的值为True
时,我们只需使用标准 GPIO 零代码打开 LED。当params
返回的值不是True
(或False
,因为只有两个值可能)时,我们会关闭 LED。
通过互联网看到 LED 灯的开关非常令人印象深刻。然而,这还不够。让我们利用前面章节中使用的一些代码,让 T.A.R.A.s 起舞。这一次,我们将利用互联网让它起舞。
为了让 T.A.R.A.S 再次起舞,我们需要确保第 14 章中使用 Python控制机器人车的代码与我们将要编写的代码位于同一目录中。
我们将首先在仪表板上创建一个舞蹈开关:
RPC set value method
更改为dance
现在我们有了开关,让我们修改代码:
import paho.mqtt.client as mqtt
import json
from RobotDance import RobotDance
THINGSBOARD_HOST = 'demo.thingsboard.io'
ACCESS_TOKEN = '<<access token>>'
robot_dance = RobotDance()
def on_connect(client, userdata, rc, *extra_params):
print('Connected with result code ' + str(rc))
client.subscribe('v1/devices/me/rpc/request/+')
def on_message(client, userdata, msg):
data = json.loads(msg.payload.decode("utf-8"))
if data['method'] == 'dance':
if data['params']:
robot_dance.lets_dance_incognito()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set(ACCESS_TOKEN)
client.connect(THINGSBOARD_HOST, 1883, 60)
client.loop_forever()
internet-dance.py
现在转到仪表板,轻弹舞蹈开关(不幸的是,这是一个开关而不是按钮)。T.A.R.A.S 应该像在第 14 章中一样开始跳舞,使用 Python控制机器人车。
那么,我们刚才做了什么?嗯,我们使用了简单的代码,对其进行了一些修改,通过面向对象编程的强大功能,我们能够让 T.a.R.a.S 跳舞,而不需要更改甚至不需要检查我们的旧RobotDance
代码(OOP 不是最好的东西吗,因为无论你认为最好的东西是什么?)。
对于 MQTT 代码,我们所要做的就是将import
添加到RobotDance
类中,去掉冗余的 GPIO 零导入,去掉对 LED 的任何引用(因为这会导致冲突),然后修改on_message
方法以查找dance
作为方法。
RobotDance
类类型的robot_dance
对象完成所有工作。当我们在这个对象上调用lets_dance_incognito
方法时,它会将RobotWheels
、RobotBeep
、TailLights
和RobotCamera
类中用于移动的方法付诸实施。最终的结果是通过互联网上的一个开关让 T.a.R.a.S 跳舞。
在本章中,我们进一步研究了用于距离感测信息的仪表板模拟仪表。我们对它进行了美容修饰,然后改变了范围并将其公开。然后我们将注意力转向通过互联网控制 T.A.R.A.S。通过使用一个简单的程序,我们能够打开 T.a.R.a.S.上的绿色 LED。使用仪表板开关。我们掌握了这些知识,修改了代码,通过另一个仪表板开关让 T.A.R.A.S 跳舞。
在第 17 章构建 JavaScript 客户端中,我们将继续编写 JavaScript 客户端,通过互联网控制 T.a.R.a.S
print(data)
行返回的信息人类无法读取。RobotDance
类中的哪种方法让 T.A.R.A.S 跳舞?json
数据的库称为jason
。on_message
方法从msg
返回多少个键值对?因为我们只是简单地提到了 ThingsBoard,所以最好在查看他们的文档 https://thingsboard.io/docs/guides/ 。