领先的免费Web技术教程,涵盖HTML到ASP.NET

网站首页 > 知识剖析 正文

构建机器人指南:6 创建机器人网页应用程序

nixiaole 2025-01-23 20:12:59 知识剖析 12 ℃

本章涵盖

  • 创建一个适用于桌面和移动设备的网络应用程序来控制机器人
  • 使用网页浏览器工具测量 Web 应用程序性能
  • 使用 Tornado 模板创建动态页面
  • 启用增强的网络日志记录以检测网络请求失败

本章将教你如何构建一个控制机器人网页应用程序。该应用程序在桌面电脑和手机上都能良好运行。通过该应用程序,用户将能够访问机器人所有的运动范围,并可以使用命令来测量应用程序的网络性能,端到端。在构建应用程序的过程中,你将学习到测量应用程序性能的实用技巧,以及检测和修复某些类型的网页请求失败的方法。

网络应用程序提供了一个强大的平台,使人类操作员能够控制机器人。网络应用程序可以通过桌面应用程序和移动设备访问。它们在主要桌面操作系统(即 Windows、Mac 和 Linux)上也能一致运行。

6.1 硬件堆栈

图 6.1 显示了硬件堆栈,本章中使用的具体组件已被突出显示。在本章中,我们可以使用鼠标作为人机交互设备,通过我们的网络应用程序与机器人进行交互。

该网络应用程序可以通过使用以太网端口的有线网络或使用 Wi-Fi 硬件的无线网络进行访问。移动访问的最佳用户体验是通过 Wi-Fi 连接,因为它提供了完全的便携性。当从桌面访问网络界面时,可以使用鼠标作为人机接口设备,通过点击所需的机器人移动按钮来控制机器人。在后面的章节中,我们将使用键盘和操纵杆来控制机器人。

6.2 软件栈

本章中使用的具体软件的详细信息在图 6.2 中描述。这里将创建三个主要应用程序。第一个是一个基本的 Web 应用程序,用于显示机器人服务器上的当前时间( basic_web )。然后,我们将创建一个应用程序,使机器人向前和向后移动( forward_web )。最后,将创建一个移动友好的应用程序,提供全范围的机器人运动命令( full_web )。将使用 Tornado Web 框架来创建这些 Web 应用程序。该框架的内置模板功能将用于创建动态内容。将使用 datetime 和 os Python 模块来计算服务器上的时间并读取环境变量中的值。

6.3 在网络上前后移动机器人

我们创建的第一个网络应用程序将执行基本的前进和后退机器人运动。我们需要创建一个网络应用程序以满足以下要求:

  • 应该创建一个 Python 网络应用程序,允许用户前后移动机器人。
  • 该网络应用程序应使用 HTML5 标准。
  • 用户界面必须适合桌面和移动设备。

HTML5 是用于网络的标记语言的最新版本,与旧版本相比,它提供了更丰富的功能。因此,我们将其作为应用程序的要求。

6.3.1 创建一个基本的 web 应用程序

让我们迈出一些简单的第一步,创建一个在机器人网络服务器上显示时间的网络应用程序。第一步是导入所有必需的模块。从 Tornado 中,我们导入 IOLoop 、 RequestHandler, 和 Application ,正如我们在前面的章节中所做的那样,以设置和运行我们的网络应用程序。然后我们导入 enable_pretty_logging 以启用日志输出。 datetime 对象将用于获取当前时间。 dirname 函数将获取路径的目录名称。 os 模块将用于访问环境变量:

from tornado.ioloop import IOLoop
from tornado.web import RequestHandler, Application
from tornado.log import enable_pretty_logging
from datetime import datetime
from os.path import dirname
import os

Tornado web 框架具有强大的调试模式,提供自动重载和生成错误页面等功能,这些功能在开发和调试 Web 应用程序时都非常有帮助。下一行代码将全局变量 DEBUG 设置为 true 或 false,具体取决于环境变量 ROBO_DEBUG 是否已定义。通过这种方式,可以将相同的代码用于开发或生产环境,并且其调试行为可以通过环境变量在代码库之外进行定义:

DEBUG = bool(os.environ.get('ROBO_DEBUG'))

下一步是将 TEMPLATE_PATH 设置为模板目录的路径。该目录将包含用于生成 HTML 内容的 Tornado 模板文件。此路径会自动计算为与 Python 代码位于同一目录下的名为 templates 的子目录。将所有 HTML 模板文件放置在此目录中:

TEMPLATE_PATH = (dirname(__file__) + '/templates')

我们现在可以定义处理传入请求的 MainHandler 对象。它将计算当前时间并将值作为字符串保存在名为 stamp 的变量中。然后,使用 stamp 变量渲染 basic.xhtml 模板并发送到网页浏览器:

class MainHandler(RequestHandler):
    def get(self):
        stamp = datetime.now().isoformat()
        self.render('basic.xhtml', stamp=stamp)

最后一段代码调用 enable_pretty_logging 以启用日志输出,并使用应用程序设置定义 settings 。然后将这些设置提供给 Application ,并启动应用程序服务器:

enable_pretty_logging()
settings = dict(debug=DEBUG, template_path=TEMPLATE_PATH)
app = Application([('/', MainHandler)], **settings)
app.listen(8888)
IOLoop.current().start()

完整的脚本可以保存为 basic_web.py 在树莓派上。

图 6.1 basic_web.py : 显示机器人时间的网络应用程序

#!/usr/bin/env python3
from tornado.ioloop import IOLoop
from tornado.web import RequestHandler, Application
from tornado.log import enable_pretty_logging
from datetime import datetime
from os.path import dirname
import os
 
DEBUG = bool(os.environ.get('ROBO_DEBUG'))
TEMPLATE_PATH = (dirname(__file__) + '/templates')
 
class MainHandler(RequestHandler):
    def get(self):
        stamp = datetime.now().isoformat()
        self.render('basic.xhtml', stamp=stamp)
 
enable_pretty_logging()
settings = dict(debug=DEBUG, template_path=TEMPLATE_PATH)
app = Application([('/', MainHandler)], **settings)
app.listen(8888)
IOLoop.current().start()

在我们执行脚本之前,我们应该创建 basic.xhtml 模板。我们将逐一查看这个模板文件的每个部分。文件的第一行是必需的,用于向网页浏览器声明该文件使用 HTML5。然后,我们有我们的开头 html 标签,它将文档语言定义为英语:


下一部分是 HTML 文档的 head 部分。网站标题已提供,然后使用 meta 标签设置 viewport 元数据,以便 Web 应用程序在桌面和移动浏览器上正确显示。接下来,页面的字体设置为 Verdana ,使用 style 标签:


  Robot Web
  

模板的最后部分包含文档的 body 部分。 h1 标签用于提供标题内容,最后, stamp 模板变量被放置在该标题下,以显示机器人的当前时间:


Robot Web

{{ stamp }}

该模板可以保存在 Pi 的模板目录中,命名为 basic.xhtml 。

图 6.2 basic.xhtml : 显示机器人时间的 HTML 用户界面




  Robot Web
  



Robot Web

{{ stamp }}

我们现在可以执行 basic_web.py 来运行网络服务器。您可以通过访问地址 http://robopi:8888 从您网络上的计算机访问网络应用程序。确保在计算机上更新 hosts 文件,以便为 robopi 添加条目,如第 5 章所述。您还可以通过将 URL 中的 robopi 替换为您机器人的 IP 地址来访问网络应用程序。当从移动设备访问网络应用程序时,使用 IP 地址将是一个更简单的选项。

当您访问网络应用程序时,它将显示机器人服务器上的当前时间。刷新页面以查看更新时间,并确认服务器能够响应多个请求。图 6.3 显示了应用程序的外观。

6.3.2 检测失败的请求

因为我们调用了 enable_pretty_ logging ,我们可以将服务器日志输出到终端。我们可以检查这个输出,以查看所有对 web 服务器的传入请求和给定的响应。尝试从多个浏览器或计算机再次访问 web 应用程序。接下来是从多个浏览器和计算机访问应用程序后的日志输出:

$ basic_web.py 
[I 221213 17:20:27 web:2271] 200 GET / (10.0.0.30) 7.99ms
[W 221213 17:20:27 web:2271] 404 GET /favicon.ico (10.0.0.30) 1.27ms
[I 221213 17:20:33 web:2271] 200 GET / (10.0.0.30) 2.21ms
[W 221213 17:20:34 web:2271] 404 GET /favicon.ico (10.0.0.30) 1.84ms
[I 221213 17:20:35 web:2271] 200 GET / (10.0.0.30) 1.98ms
[I 221213 17:20:35 web:2271] 200 GET / (10.0.0.30) 2.23ms
[W 221213 17:23:51 web:2271] 404 GET /favicon.ico (10.0.0.15) 1.82ms
[I 221213 17:23:53 web:2271] 200 GET / (10.0.0.15) 2.36ms
[I 221213 17:23:54 web:2271] 200 GET / (10.0.0.15) 2.32ms
[I 221213 17:23:55 web:2271] 200 GET / (10.0.0.15) 2.23ms

我们可以看到,在页面加载后,浏览器尝试获取一个名为 favicon.ico 的文件,但以“404 未找到”的 HTTP 错误失败。这是因为我们尚未定义处理这些请求的适当方法,因此它们失败了。在下一个升级中,我们可以解决这个问题,并在更改后检查服务器日志以确认情况已得到解决。这个日志输出也是查看 Tornado 提供响应所需时间的好方法,因为响应时间也会出现在日志输出中。

6.3.3 使用网络应用程序推动机器人前进

现在我们将向我们的应用程序添加前进和后退的运动。我们将再次导入 motor 模块来控制机器人的运动:

import motor

Application 对象将增强以处理不同的请求 URL,并从请求的路径中解析动作。正则表达式 /([a-z_]*) 用于匹配由小写字母和下划线字符组成的路径。此模式将匹配所有可用的移动命令:

app = Application([('/([a-z_]*)', MainHandler)], **settings)

我们现在更新 get 方法以接收 name 参数并渲染 forward.xhtml 模板:

def get(self, name):
    stamp = datetime.now().isoformat()
    self.render('forward.xhtml', stamp=stamp)

如前几章所述,我们将仅在接收到 post 请求时处理移动命令。 post 方法将检查 name 变量的值并调用相关的移动函数。然后,它将使用 redirect 方法将浏览器重定向到 web 应用程序主页:

def post(self, name):
    if name == 'forward':
        motor.forward()
    if name == 'backward':
        motor.backward()
    self.redirect('/')

完整的脚本可以保存为 forward_web.py 在树莓派上。

图 6.3 forward_web.py : 用于使机器人前进和后退的网络应用程序

#!/usr/bin/env python3
from tornado.ioloop import IOLoop
from tornado.web import RequestHandler, Application
from tornado.log import enable_pretty_logging
from datetime import datetime
from os.path import dirname
import os
import motor
 
DEBUG = bool(os.environ.get('ROBO_DEBUG'))
TEMPLATE_PATH = (dirname(__file__) + '/templates')
 
class MainHandler(RequestHandler):
    def get(self, name):
        stamp = datetime.now().isoformat()
        self.render('forward.xhtml', stamp=stamp)
 
    def post(self, name):
        if name == 'forward':
            motor.forward()
        if name == 'backward':
            motor.backward()
        self.redirect('/')
 
enable_pretty_logging()
settings = dict(debug=DEBUG, template_path=TEMPLATE_PATH)
app = Application([('/([a-z_]*)', MainHandler)], **settings)
app.listen(8888)
IOLoop.current().start()

我们现在可以升级 HTML 模板。为了解决 favicon 问题,我们在模板的 head 部分使用以下 HTML。这为页面设置了无图标,从而指示网页浏览器不从 web 服务器获取 favicon 文件:

在文档的主体部分,我们添加了两个表单。每个表单将使用 post 方法提交其数据,提交到 forward 路径或 backward 路径。每个表单的提交按钮都有一个与该表单的移动操作相匹配的标签:

该模板可以保存在 Pi 的模板目录中,命名为 forward.xhtml 。

图 6.4 forward.xhtml : HTML 用于使机器人前进和后退




  Robot Web
  
  



Robot Web

{{ stamp }}

我们现在可以执行 forward_web.py 来运行网络服务器。当您访问网络应用程序时,按下前进和后退按钮以使机器人向前和向后移动。图 6.4 显示了应用程序现在带有这些新按钮的样子。我们可以使用该应用程序检查会话的日志输出:

$ forward_web.py 
[I 221213 17:37:29 web:2271] 200 GET / (10.0.0.30) 7.99ms
[I 221213 17:37:34 web:2271] 302 POST /forward (10.0.0.30) 222.82ms
[I 221213 17:37:34 web:2271] 200 GET / (10.0.0.30) 2.28ms
[I 221213 17:37:35 web:2271] 302 POST /backward (10.0.0.30) 223.56ms
[I 221213 17:37:35 web:2271] 200 GET / (10.0.0.30) 2.25ms
[I 221213 17:37:36 web:2271] 302 POST /backward (10.0.0.30) 224.18ms
[I 221213 17:37:36 web:2271] 200 GET / (10.0.0.30) 2.22ms


在日志输出中,我们可以看到机器人向前移动了一次,然后向后移动了两次。从日志中,我们可以看到渲染主页面通常需要 2 毫秒。执行机器人移动大约需要 224 毫秒。在 motor 模块中,机器人移动的默认持续时间设置为 200 毫秒。因此,这些数字是我们所期望的。最后,我们可以看到“未找到 favicon 错误”也已解决,因为它们不再出现在请求日志中。

深入探讨:HTML5

HTML5 是用于网络的标记语言的最新版本。该标准由网络超文本应用技术工作组(WHATWG)维护,该工作组是主要浏览器供应商(苹果、谷歌、Mozilla 和微软)的联盟。HTML 生活标准(https://w3.org/TR/html5)提供了有关 HTML 元素和语法的完整细节。它是该标准的全面参考。

本章中大量使用 HTML 表单来向机器人服务器提交所需的移动动作。Mozilla 关于网页表单的指南(
https://developer.mozilla.org/Learn/Forms)是一个很好的资源,可以探索如何创建具有不同提交选项的表单,以及表单本身包含的不同输入元素。

6.4. 创建一个完整交互的网络应用程序

我们现在可以继续创建一个可以调用所有机器人运动功能的网络应用程序。我们需要创建一个网络应用程序,以满足以下要求:

  • 应该创建一个 Python 网络应用程序,允许用户将机器人向前、向后、向右、向左移动,并在两个方向上旋转。
  • 应该创建一个按钮来调用无操作 noop 函数,以便在网页浏览器中进行性能测量。
  • 用户界面中的按钮应使用一种布局,能够舒适地支持移动触控和桌面鼠标交互。

6.4.1 创建全运动应用程序

在 Python 方面,我们几乎完成了。我们可以对之前的应用程序进行一些小修改,以启用所有移动功能。我们将对 get 方法进行小修改,以便它使用我们新的 full.xhtml 模板:

    def get(self, name):
        stamp = datetime.now().isoformat()
        self.render('full.xhtml', stamp=stamp)

post 方法现在将增强以从 motor 模块查找所需的移动功能,然后调用该功能。之后,我们将被重定向到应用程序主屏幕:

    def post(self, name):
        func = getattr(motor, name)
        func()
        self.redirect('/')

完整的脚本可以保存为 full_web.py 在树莓派上。

图 6.5 full_web.py : 支持所有机器人移动动作的 Web 应用程序

#!/usr/bin/env python3
from tornado.ioloop import IOLoop
from tornado.web import RequestHandler, Application
from tornado.log import enable_pretty_logging
from datetime import datetime
from os.path import dirname
import os
import motor
 
DEBUG = bool(os.environ.get('ROBO_DEBUG'))
TEMPLATE_PATH = (dirname(__file__) + '/templates')
 
class MainHandler(RequestHandler):
    def get(self, name):
        stamp = datetime.now().isoformat()
        self.render('full.xhtml', stamp=stamp)
 
    def post(self, name):
        func = getattr(motor, name)
        func()
        self.redirect('/')
 
enable_pretty_logging()
settings = dict(debug=DEBUG, template_path=TEMPLATE_PATH)
app = Application([('/([a-z_]*)', MainHandler)], **settings)
app.listen(8888)
IOLoop.current().start()

下一步将升级 HTML 模板。 body 中的内容将进行多项增强。页面标题中的文本将添加链接,以便用户可以点击页面标题重新加载页面。每个移动功能的按钮都放置在屏幕上。屏幕的布局设计为将相似的操作分组在同一行。第一行有前进和后退按钮。第二行有左转和右转按钮。第三行显示左旋和右旋按钮。最后一行呈现无操作按钮。这些按钮使用 HTML5 命名的字符引用,以便按钮具有图形指示其功能:


Robot Web

{{ stamp }}







现在我们可以通过更新样式标签来为页面上的内容设置样式。我们将页面中的内容居中,并移除页面上链接的默认下划线文本装饰样式。接下来,我们开始为页面上的按钮设置样式。它们的字体大小增大了三倍,并添加了适量的边距,以提供按钮之间良好的间距。这种布局和间距使得在触摸界面上用手指按压按钮变得更容易,因为按钮不会紧挨在一起。最后,所有按钮的高度和宽度都设置为 60 像素,以创建统一的外观:

该模板可以保存在 Pi 的模板目录中,命名为 full.xhtml 。

图 6.6 full.xhtml : 支持所有机器人移动动作的 HTML 用户界面




  Robot Web
  
  



Robot Web

{{ stamp }}







我们现在可以执行 full_web.py 来运行网络服务器。当您访问网络应用程序时,按下不同的移动按钮以使机器人执行每个可用的移动。接下来是使用该应用程序的会话日志输出:

$ full_web.py 
[I 221214 15:37:32 web:2271] 200 GET / (10.0.0.30) 4.75ms
[I 221214 15:37:34 web:2271] 302 POST /forward (10.0.0.30) 223.77ms
[I 221214 15:37:34 web:2271] 200 GET / (10.0.0.30) 5.26ms
[I 221214 15:37:35 web:2271] 302 POST /backward (10.0.0.30) 223.29ms
[I 221214 15:37:35 web:2271] 200 GET / (10.0.0.30) 4.77ms
[I 221214 15:37:35 web:2271] 302 POST /left (10.0.0.30) 222.85ms
[I 221214 15:37:35 web:2271] 200 GET / (10.0.0.30) 4.78ms
[I 221214 15:37:36 web:2271] 302 POST /right (10.0.0.30) 222.96ms
[I 221214 15:37:36 web:2271] 200 GET / (10.0.0.30) 4.81ms
[I 221214 15:37:40 web:2271] 302 POST /spin_left (10.0.0.30) 223.67ms
[I 221214 15:37:40 web:2271] 200 GET / (10.0.0.30) 4.80ms
[I 221214 15:37:41 web:2271] 302 POST /spin_right (10.0.0.30) 223.42ms
[I 221214 15:37:41 web:2271] 200 GET / (10.0.0.30) 4.84ms
[I 221214 15:37:41 web:2271] 302 POST /noop (10.0.0.30) 1.83ms
[I 221214 15:37:41 web:2271] 200 GET / (10.0.0.30) 4.87ms

从日志中,我们可以看到每个不同的移动功能成功执行,然后在调用每个功能后主页面加载。值得注意的是,对 noop 页面的调用大约在 2 毫秒内加载,这表明性能良好。

6.4.2 网络界面设计

图 6.5 显示了网络应用程序在桌面和笔记本电脑用户中的外观。每个按钮使用的图标反映了将要执行的动作。因此,指向前方和后方的箭头表示机器人向前和向后移动。右、左和旋转功能具有类似的图形表示。无操作动作用一个 X 表示,以指示它不会导致任何移动。

图 6.6 显示了应用在移动设备上的外观。按钮使用了较大的字体,并且宽度和高度都足够大,以便在触摸屏上能够舒适地按压。按钮之间的宽敞间距也防止了它们的拥挤。整个应用程序适合在一个屏幕上显示,因此所有功能都可以在不需要滚动的情况下访问。

现实世界中的机器人:通过网络应用控制机器人

通过网络应用程序控制机器人比使用桌面应用程序提供了更方便的访问,因为它们可以通过移动设备访问。在工厂车间通过智能手机访问和控制机器人为操作员提供了更大的活动自由度,而不是拖着一台笔记本电脑。

在需要时,它们还支持来自大屏幕设备的访问,例如平板电脑或笔记本电脑。可以设计不同的用户界面,以更好地支持大屏幕设备。通过这种方式,用户可以获得两全其美的体验。

现代网络应用程序也非常可扩展。我们将在后面的章节中看到如何将机器人摄像头的视频流添加到我们的网络应用程序中。这使得机器人操作员能够准确地看到机器人所看到的内容。

6.4.3 在浏览器中测量应用性能

图 6.7 显示了如何在浏览器中测量 Web 应用程序性能。Firefox 和 Google Chrome 浏览器都具有一个名为开发者工具的内置功能,提供许多丰富的功能,例如测量应用程序性能。一旦在浏览器中访问该工具,点击网络选项卡。图 6.7 显示了在请求机器人向右旋转时进行的示例测量。从测量结果可以看出,调用向右旋转动作花费了 229 毫秒,然后重定向并加载主页面花费了 14 毫秒。这些数字与我们在终端的日志输出中看到的服务器数据相匹配。当尝试诊断 Web 应用程序的性能问题时,这个工具非常方便。

6.4.4 网络硬件设备

图 6.8 显示了该网络应用在运行 iOS 操作系统的智能手机上的外观。智能手机提供了最高的便携性,因为它们足够小,可以放进口袋。使用它们的缺点是屏幕较小,并且我们只能使用触摸屏界面与应用进行交互。

图 6.9 显示了在平板电脑上运行的应用程序。这些类型的硬件设备提供了更大的屏幕,使我们能够在用户界面中放置更多的控件。

在各种不同屏幕尺寸和网页浏览器的设备上测试您的网络应用程序通常是个好主意,这样您可以发现可能在特定设备或浏览器上出现的任何问题。


摘要

  • 通过 Wi-Fi 访问机器人可以提供最佳用户体验,因为机器人和手机都具有完全的便携性。
  • Tornado web 框架的内置模板功能用于在应用程序中创建动态内容。
  • 输出服务器日志的一个好处是我们可以看到所有对 web 服务器的请求及其响应。
  • 按钮使用较大的字体,并且宽度和高度都足够大,以便在触摸屏上可以舒适地按压。
  • Firefox 和 Google Chrome 浏览器都内置了一个名为开发者工具的功能,提供了许多丰富的特性,例如测量应用程序性能。

Tags:

最近发表
标签列表