Exercising Misty 的可扩展性





0/5 (0投票)
解构 Misty 的“跟随球”技能
Misty 深知玩乐的重要性不亚于工作。因此,她愿意冒着弄脏草坪的风险,来开发她的 “追逐球”技能。
在此技能中,Misty 连接到一个微控制器,利用 Pixy2 视觉传感器的物体识别能力,追逐在房间里移动的足球。以下是其工作原理的高层概述:
- Pixy2(经过“训练”以识别和检测足球)将图像数据发送到连接到 Misty 的微控制器。
- 微控制器计算 Misty 与球的距离和方向,然后通过 Misty 背部内置的 UART 串行端口将这些值发送到 Misty 上的代码。
- 当 Misty 收到这些数据时,她将其转换为其驱动命令的线速度和角速度值,并朝球移动或远离球。
- Pixy2 将更新的信息发送给微控制器,然后使用新的图像数据重复此过程。
本文将更详细地介绍每个要点,以便您可以为 Misty 构建自己的“追逐球”技能。我们将从 Pixy2 开始。
准备 Pixy2
Pixy2 是一款适用于机器人的闪电般快速的视觉传感器。训练 Pixy2 识别物体就像将物体放在传感器前面并按一下按钮一样简单。它专为 轻松连接微控制器(如 Arduino 或 Raspberry Pi)而设计,Pixy 提供了简化代码中使用图像数据的库。
在“追逐球”技能中,我们使用微控制器上的 ISCP 连接器将 Pixy 连接到 Misty(兼容 Arduino 的)扩展板。我们使用 3D 打印的附件 将传感器定位在 Misty 底座的前方中央。完成此设置后,我们通过将 Pixy2 指向正确方向并按住 Pixy2 上的按钮来“教会”传感器识别足球。
现在 Pixy2 已经识别出物体,我们可以开始编写微控制器的代码了。
准备微控制器
在此技能中,Misty 使用其自身的 兼容 Arduino 的扩展板 中的微控制器。此微控制器是 Arduino Uno 的克隆,但进行了几项重要更改。其中一项更改是添加了磁铁,用于将板固定到 Misty 的背部,从而直接连接到其 UART 串行端口。
我们称在 Misty 的兼容 Arduino 的扩展板上运行的代码为“草图”。您可以使用 编程 Arduino Uno 所使用的相同工具 来编写草图。为了处理来自视觉传感器的数据,我们将 Pixy2 Arduino 库 包含在草图中。
#include <Pixy2.h> // This is the main Pixy object Pixy2 pixy;
我们在草图的 setup()
函数中初始化 pixy 对象。来自 Serial 库的 Serial.begin()
函数会打开一个串行端口,并将数据传输速率设置为 9600 波特(这是与 Misty 的 UART 串行端口通信的速率)。我们还设置了几个用于计算球运动的变量的值。
void setup() { //Serial.print("Starting...\n"); pixy.init(); OLD = 0; towards = 0; Serial.begin(9600); }
在执行其驱动命令之前,Misty 需要了解她相对于球的位置。具体来说,她需要知道她的方向,即她所面向的方向与球的位置之间的夹角。她还需要知道球的距离以及它的当前运动方向。
此草图中的 loop()
函数每 200 毫秒将所有这些信息传输给 Misty 一次。在 loop 函数中,我们调用 pixy.ccc.getBlocks()
来返回视觉传感器检测到的对象的数据。这些数据包括对象在图像中的宽度和高度(以像素为单位),这使我们可以近似计算球离 Misty 的距离。尺寸越大表示越近,尺寸越小表示越远。
我们通过计算图像中心与球中心在图像中的 X 坐标之间的差值来获得 Misty 的方向。为了确定球的移动方向,我们将此值与上一个循环的方向角进行比较。
然后,我们将所有这些数据——size
(大小)、pan
(方向)和方向——打包成一个字符串化的 JSON 对象,并使用 Serial.println()
发送给 Misty。在 GitHub 上查看草图,或参阅下面的 loop()
函数。
void loop() { pixy.ccc.getBlocks(); if (pixy.ccc.numBlocks) { // ~Max size of the ball in pixels sizeMin = min(pixy.ccc.blocks[0].m_width, pixy.ccc.blocks[0].m_height); sizeMax = max(pixy.ccc.blocks[0].m_width, pixy.ccc.blocks[0].m_height); if (sizeMin >10) { // Heading to ball panOffset = (int32_t)pixy.frameWidth/2 - (int32_t)pixy.ccc.blocks[0].m_x; // Calculate direction of motion NEW = panOffset; if (abs(NEW-OLD) > 20) { //towards = sign(NEW-OLD,DEC)*1; if (NEW-OLD <0) { towards = -1;} else { towards = 1;} OLD = NEW; count = 0; } if (abs(NEW-OLD) < 10){ count++; if (count>30){ towards = 0; } } // This data is sent to misty Serial.println("{\"pan\":\""+String(panOffset)+"\",\"size\":\""+String(sizeMax)+"\",\"direction\":\""+String(towards)+"\"}"); } } delay(200); }
接下来,我们将设置 Misty 上运行的 JavaScript 代码,以处理传入数据并计算其驱动命令的值。
编码 Misty
Misty 上运行的代码处理微控制器通过其 UART 串行端口发送的每条消息。它将这些数据转换为参数,当这些参数传递给 Misty 的驱动命令时,可以将她移近(或远离)球。
为了在技能中管理此功能,我们使用 misty.RegisterEvent()
来注册 StringMessage
事件。每次微控制器通过 Misty 的 UART 串行端口的接收器(RX)引脚发送消息时,都会发生这些事件。
function sub_arduino(){ misty.AddReturnProperty("StringMessage", "StringMessage"); misty.RegisterEvent("StringMessage", "StringMessage", 0, true); }
默认情况下,当发生 StringMessage
事件时,技能会查找 _StringMessage()
回调函数来传递事件数据。这些数据包括微控制器发送给 Misty 的任何消息。您在 _StringMessage()
回调函数的定义中定义如何处理这些数据。
function _StringMessage(data) { // Process incoming message from Misty's UART serial }
在“追逐球”技能中,_StringMessage()
解析来自微控制器的数据,并将其转换为 misty.Drive()
方法的 linearVelocity
(线速度)和 angularVelocity
(角速度)参数的值。这些值都是介于 -100 和 100 之间的整数。对于 linearVelocity
,值为 -100 表示“以最大速度向后行驶”,而 100 表示“以最大速度向前行驶”。对于 angularVelocity
,-100 表示“以最大速度顺时针旋转”,而 100 表示“以最大速度逆时针旋转”。
我们使用 Pixy2 图像中球的大小来计算适当的 linearVelocity
参数值。如果球看起来比应有的要小,Misty 就会朝它行驶,如果它看起来更大,她就会后退。angularVelocity
的值与 Misty 的方向相关——我们计算出一个值,让 Misty 向球旋转或以曲线行驶。参阅 followBall.js 中的 第 35-72 行,了解这些计算是如何在代码中实现的。
Misty 每次接收到新的图像数据时都会重新计算这些值,因此她会不断地调整自己的速度和相对于球的位置。所有这些加在一起,造就了一个动态且可爱的机器人。观看视频,了解我们的意思。
可扩展性意味着无限的潜力
您很难找到一款硬件能够满足您所有奇思妙想的机器人。这就是可扩展平台如此引人注目的原因。一款拥有强大原生功能,并能通过第三方硬件进行增强的机器人,拥有大量的就业机会。
不要错过 GitHub 上“追逐球”技能的完整存储库,如果您对更多关于机器人的讨论感兴趣,请务必加入 社区论坛的讨论。
阅读 Misty Robotics 博客上的 这篇文章(及其他文章)。