亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

带有 Arduino 和 BitVoicer 服务器的 2WD 语音控制机器人

组件和用品

Arduino UNO
× 1
Pololu Dual MC33926 电机驱动屏蔽
× 1
SparkFun XBee Shield
× 1
Microchip RN171VX 模块
× 1
SparkFun 驻极体麦克风突围
× 1
2WD 机器人汽车底盘
× 1
Texas Instruments LM1117 (TO-220) 稳压器
× 1
电容 10 µF
× 1
LED(通用)
× 4
电阻 330 ohm
× 4
AA 电池
× 4
9V 电池(通用)
× 1
9V 至桶形插孔适配器
× 1
跳线(通用)
× 17
普通铜线
× 1
用于固定的螺钉和柔性塑料夹
× 1

必要的工具和机器

烙铁(通用)
钳子
螺丝刀

应用和在线服务

BitVoicer Server 1.0

关于这个项目

在本教程中,我将展示如何构建一个 2WD 声控机器人。虽然我只控制直流电机来移动机器人,但同样的方法可以用于声控步进电机和伺服电机,所以如果你打算构建任何执行机械运动的声控机器人,本教程可以作为供您的项目参考。

要构建这个机器人,您基本上需要一个 2 轮底盘、一个 Arduino 板、一个直流电机驱动板、一个 BitVoicer 服务器许可证、一个 WiFi 模块和一个前置放大麦克风。关于组件,市场上有各种各样的组件,您可以使用不同的组合获得相同的结果。在第一步中,我给出了机器人中使用的一些组件的一些细节,因此如果您需要更改其中的某些组件,只需寻找具有相似功能的组件即可。

将执行以下程序将语音命令转换为机器人动作:

  • 1. Sparkfun Electret Breakout 板将捕获和放大音频波;
  • 2.放大后的信号将在 Arduino 中使用其模数转换器 (ADC) 进行数字化和缓冲;
  • 3.音频样本将使用 Microchip WiFi 模块流式传输到 BitVoicer 服务器;
  • 4. BitVoicer Server 将处理音频流并识别其中包含的语音;
  • 5.识别的语音将映射到将发送到 Arduino 的预定义命令;
  • 6. Arduino 将识别命令并定义将使用哪些直流电机、使用多长时间以及以何种速度使用;
  • 7.电机驱动器将被激活以提供驱动电机所需的电压和电流。

材料清单:

  • Arduino UNO:~U$ 25.00
  • Pololu Dual MC33926 电机驱动器屏蔽:美国 29.95
  • SparkFun XBee 盾:14.95 美元
  • 带天线的 Microchip RN171VX 模块:34.95 美元
  • SparkFun 驻极体麦克风突破:7.95 美元
  • BitVoicer Server 1.0:8.90 美元
  • 2WD 机器人汽车底盘:15.95 美元
  • Texas Instruments LM1117 (TO-220) 稳压器:~U$ 1.95
  • 10μF 电解电容器:~U$ 0.35
  • 4 个 LED:~US 1.00
  • 4 x 330 欧姆电阻器:~U$ 0.75
  • 4 节 1.5V AA 电池:~US 2.00
  • 9V 电池:~US 2.00
  • 9V 转筒式插孔适配器:~US 2.50
  • 跳线和普通电线:~U$ 2.00
  • 用于固定的螺钉和柔性塑料夹
  • 烙铁和焊锡

第 1 步:了解组件

在这一步中,我提供了一些关于机器人组件的重要信息以及如何准备安装。

首先,机器人的心脏:Arduino UNO R3。虽然我使用的是 Arduino UNO,但您可以使用其他 Arduino 板来安装您的机器人。我决定使用 Arduino UNO,因为它是迄今为止最受欢迎的 Arduino 板,更多的人将能够重建这个机器人。如果您有 Arduino DUE,您还可以像我在本教程中所做的那样为您的机器人添加语音响应。

为了移动直流电机,我使用了这个 Pololu 盾牌。它是一款双电机驱动器,能够控制 5 至 28V 直流电机,并为每个电机提供高达 3A 的连续电流。虽然我认为这是一个非常好的盾牌,但在 Pololu 的产品中给我印象最深的是他们清晰而详细的文档。此外,Pololu 提供了一个 Arduino 库,可以非常简单地控制电机。您只需将速度和方向(负值或正值)传递给 setSpeeds 功能。如果您选择使用其他直流电机驱动器,请注意驱动器使用的引脚,因为它们不能与机器人使用的任何其他引脚冲突。 Pololu 扩展板使用以下 Arduino 引脚:数字 4、7、8、9、10 和 12;类比 0 和 1;地面;和 5V。这里最重要的方面是只有引脚 9 和 10 用作 PWM 引脚,并且用于在这些引脚上生成脉冲的定时器与 BitSophia 的 BVSMic 类使用的定时器(UNO 上的定时器 2)不同。

为了与服务器建立通信并访问 BitVoicer Server 服务,我使用了 Microchip WiFi RN171VX 模块。该模块的两个主要特点是:所有通信都可以通过串口以简单的方式完成;并且该模块与大多数流行的 XBee 模块具有相同的外形尺寸。换句话说,如果你已经有了 XBee 防护罩,你很可能不需要购买我在这个机器人中使用的 Sparkfun 防护罩。

将 XBee 防护罩与 Microchip WiFi 模块配合使用,可以非常轻松地安装机器人。但是,我发现这种组合存在问题。众所周知,无线电工作极其复杂,被一些人视为“巫毒魔法”。嗯,我注意到当 WiFi 适配器打开并传输数据时,Arduino ADC 测量的音频信号中出现强烈干扰。我无法准确地确定这种干扰的来源,但我有两个可能的来源:模块峰值电流消耗(高达 240mA)未正确解耦并损害提供给 Arduino ADC 的参考电压;或者天线发出的信号被模块正下方的一些裸露的引脚接收。通常,WiFi 模块制造商会指示设计人员避免在天线附近放置任何东西(甚至地平面),以防止此类问题的发生。

为了纠正上述问题,我将一个 3.3V 稳压器和一个 10μF 电解电容器焊接到 Sparkfun 屏蔽罩上,以便它们可以为 Arduino ADC 提供参考电压。 Sparkfun 驻极体麦克风使用相同的电源。它解决了我在 BitVoicer 服务器管理器中看到的峰值音量问题。即使在静音期间,服务器监视器中的音频电平也高达 35 (0-100)。如果您在项目中看到同样的事情发生,请调查 Arduino ADC 测量的音频信号发生了什么。

我决定我还要使用 Sparkfun 盾牌中可用的原型空间来焊接一些 LED,这些 LED 会告诉某些 BitVoicer 服务器功能的状态。在下图中,从左到右,LED 显示以下信息:

  • 指示 BitVoicer 服务器是否正在运行和/或连接是否保持活动状态;
  • 表示数据转发服务是否正在运行;
  • 指示语音识别引擎是否已分配给Arduino;
  • 指示我们是否处于激活词激活期。仅当识别出激活词时,此 LED 才会亮起。

关于前置放大驻极体麦克风,市场上有很多可供选择的选择:Sparkfun、Adafruit、RoboCore、Hackerstore 以及许多其他选择。要使用我在本教程中发布的代码,请确保您购买的麦克风是模拟麦克风,您的 Arduino 板上有所需的电压,并且 Arduino ADC 的放大倍数足够高(驻极体麦克风通常为 100 倍)。

机器人中使用的 2WD 底盘是 ebay 上最便宜和最受欢迎的底盘之一。完整套件包含一个亚克力平台、两个塑料/橡胶轮、一个 360º 轮、两个带齿轮的直流电机(1:48 比率)、一个 4xAA 电池座、两个速度编码器盘和一组螺钉。

第 2 步:安装

让我们开始工作吧!在这一步中,您必须将所有组件安装在机箱上,如下图所示。

如果您不想在 XBee 屏蔽上焊接 LED 和稳压器,您可以将它们安装在一个小面包板上,如下图所示。在这种情况下,请选择尺寸较小的面包板,这样您就可以将其固定在机箱上的某个位置而不会出现其他问题。

在上面的图片中,您可以注意到我做了一个铁线支架来固定麦克风。您还可以看到我在 360º 轮子周围粘了一条毡布。我采取了这两个措施,试图减少机器人在移动时产生的噪音和麦克风捕捉到的噪音。我什至切了一小块海绵来将麦克风线与支架隔离开。当然也不是100%有效,但是稍微降低了噪音,提高了语音识别的准确率。

第 3 步:设置 WiFi 模块

正如我在步骤 1 中所说,Microchip RN171VX WiFi 模块完全可以通过串口操作。这使得设置模块非常容易,因为所有命令都是通过 Arduino 串行端口发送的简单字符串。你只需要发送一个包含“$$$”的字符串进入命令模式,发送命令然后发送一个包含“exit”的字符串返回数据模式。

名为WiFi 模块设置的代码 本教程底部是我用来在家庭网络中设置 WiFi 模块的代码。您必须使用来自您的 WiFi 网络的信息更改标记为“XXXXXX”的代码部分。必须更改三个命令:

  • 设置 wlan ssid XXXXXX :将 XXXXXX 替换为您的网络名称 (SSID);
  • 设置 wlan 短语 XXXXXX :将 XXXXXX 替换为您的网络密码;
  • 设置ip地址XXXXXX :将 XXXXXX 替换为您希望为 WiFi 模块设置的 IP 地址(静态)。

在我的 WiFi 网络中,身份验证方法是 WPA2-PSK。如果您的网络使用不同的身份验证方法,您还必须更改 set wlan auth 命令。查看 WiFi 模块文档(第 4.3 节设置命令)以找出适合您网络的值。

有一个重要 有关 Sparkfun 防护罩及其小开关的详细信息(下图)。要使用其 USB 接口将代码上传到 Arduino,必须将开关设置为 DLINE 位置。对于 Arduino 使用其串口通过 WiFi 模块发送/接收数据,开关必须设置到 UART 位置。这是必要的,因为 Arduino UNO 上的 WiFi 模块和 USB 芯片在 ATmega 微控制器中使用相同的串行端口。如果开关设置为 UART 并且您尝试将代码上传到 Arduino,则 Arduino IDE 中将显示错误消息。

上传 WiFi 模块设置 将代码写入Arduino并允许Arduino设置WiFi模块,请按照以下步骤操作:

  • 1.将开关设置到 DLINE 位置;
  • 2.打开Arduino IDE,将代码粘贴并上传到Arduino;
  • 3.上传完成后,在将命令发送到 WiFi 模块之前,您将有 5 秒钟(代码开头的延迟)将开关更改为 UART 位置。如果第一个命令丢失,则其他命令都不起作用。在这种情况下,只需重置 Arduino,以便草图可以从头开始再次运行。

在模块配置过程中(大约需要 25 秒),模块 LED 的闪烁方式与其标准模式不同。这时候你就知道WiFi模块正在配置中。

模块配置完成后,尝试使用设置IP地址中指定的IP地址ping(命令提示符-->“ping [IP地址]”-->按Enter)模块 命令。如果您没有收到模块的响应,则前面的步骤出了问题。

第 4 步:规划机器人运动

虽然机器人只有两个直流电机,但它能够执行一系列复杂的运动。为了让本教程尽可能简单,我选择只定义了大约三打的基本匀速运动和几个由基本运动组合而成的复杂运动。

正如您在步骤 2 中的图片中看到的,我没有使用车轮中的旋转传感器、超声波传感器或任何其他类型的传感器来测量与物体的距离或行驶距离。这会阻止机器人执行高精度运动。但是,仅控制电机的方向和速度就可以达到足以移动机器人的精度水平。

为了能够计算每次运动所需的执行时间,您首先需要知道的是机器人的平均速度。为此,将卷尺与机器人平行放置并同时启动两个电机一两秒钟,测量行驶距离并推断速度。在我的配置中,我使用 62.5% 的最大电机速度(250/400,请参阅 Pololu Arduino 库)获得每秒 13.7 厘米的速度。换句话说,要将机器人向前移动 1 米(100 厘米),电机必须同时启动 7.299270… 秒。我选择了保持毫秒分辨率的计时,但是如果你想获得更高的运动精度,可以考虑将分辨率提高到微秒。长话短说,要将机器人移动 1 米,我必须同时激活两个电机 7299 毫秒。从这个数字开始,其他距离的一切都变成了三规则。要执行圆弧或圆周运动,一个轮必须比另一个移动得更快。要将机器人转向两侧,只需激活一个轮子或两个相反方向的轮子(以转动自己的轴)。在这里,您必须使用一些三角函数来计算每个车轮行驶的距离以及每个电机必须启动的时间。这些概念的一个很好的起点可以在以下链接中找到(我不打算在这里更进一步):http://rossum.sourceforge.net/papers/CalculationsForRobotics/CirclePath.htm 和 http://math .stackexchange.com/questions/60176/move-two-wheeled-robot-from-one-point-to-another。

正如你在下面的视频结尾看到的,我还让机器人在地板上“绘制”了一些基本的几何形状(正方形、三角形和圆形)。这些动作是通过基本动作(例如前进、转弯、前进、转弯等)的组合来实现的。这些动作的组合是在 BitVoicer 服务器语音架构中完成的,您将不会在下一步呈现的 Arduino 草图中看到它们。

第 5 步:将代码上传到 Arduino

在这一步中,您必须上传名为 Robot Source Code 的草图 ,位于本教程的底部,到 Arduino。您还可以从下面的链接下载 Arduino 草图。请记住,要将代码发送到 Arduino,您必须按照步骤 3 中的说明将 Sparkfun 扩展板上的开关设置为 DLINE 位置。在上传代码之前,您必须将 BitVoicer 服务器和 Pololu 电机驱动程序库正确安装到 Arduino IDE 中(导入 .zip 库)。

机器人源代码 :BVS_Demo3.ino

此草图的某些部分类似于我在之前的教程之一中使用的部分,用于处理与 BitVoicer Server(BVSP 和 BVSMic 类)的通信。在本教程中,我将坚持对草图新部分的解释。如果你想获得更多关于如何使用 BVSP 和 BVSMic 类的信息,我建议你参考我上面提到的教程。

  • 常量声明 :在草图的开头,我声明了整个代码中使用的一系列常量。带有电机设置的常量组定义了默认电机速度和两个方向常量。 Pololu 电机驱动程序库接受从 -400 到 +400 的电机速度值,其中零表示关闭。负值表示反向旋转,或者,如果您像我一样反转了电机线,则表示正向旋转。带有命令值的常量组是指将从 BitVoicer Server 发送的命令。在这个草图中,我只定义了 byte 的 40 个基本命令 类型,但可以结合这些命令执行更复杂的运动。
  • 执行控制变量 :在代码的开头定义了五个变量来控制命令的执行(motorSpeed , cmdDuration , cmdStartTime , cmd运行 e lastFwdCmd )。 电机速度 变量保存当前的电机速度。如果 Arduino 收到来自 BitVoicer 服务器的命令以更新电机速度,则此变量将使用速度常数定义的默认值之一进行更新。 cmdDuration 变量保存当前命令的总持续时间。根据 cmdStartTime 检查此变量 循环的所有迭代中的变量 函数 if cmdRunning 真的 .如果命令执行时间已过,RunCommand 函数被调用来停止电机。 lastFwdCmd 变量保存最后一个“go/move forward”命令。此变量用于了解上次行驶的距离,以便可以执行“回来”命令。请注意,要使用此命令,您必须先告诉机器人转身。
  • WiFi 连接 :在草图的最后,我定义了两个函数来连接和断开 BitVoicer 服务器(Connect 断开连接 )。这些函数将 Microchip WiFi 模块置于命令模式、打开或关闭 TCP/IP 连接并将模块返回到数据模式。 循环内 函数,如果连接的变量不是 true ,我称之为连接 功能。如果 BVSP 类报告服务器状态已过期,换句话说,没有收到最后一个状态请求的答复,我认为连接已丢失,我调用 Disconnect 功能。这将强制在下一次循环迭代中尝试新的连接。
  • 运行命令 功能 :每次从 BitVoicer Server 收到命令时都会调用此函数。它需要一个字节 对应于草图开头常量定义的基本命令之一的值。每个基本命令都在开关内部标识,因此可以设置适当的电机速度以及命令持续时间。在函数的最后,cmdRunning 变量设置为 true 以及 millis 返回的时间 函数存储在 cmdStartTime 多变的。这允许 Arduino 如上所述控制命令执行。如上一步所述,获取每个命令的时间(以毫秒为单位)。

第 6 步:设置 BitVoicer 服务器

在这一步中,您必须使用要识别的句子和将发送到 Arduino 的命令构建 BitVoicer 服务器语音架构。在此步骤的末尾,有两个指向包含本教程中使用的所有 BitVoicer 服务器解决方案对象的文件的链接。如果不想一一创建所有解决方案对象,可以使用这些文件导入(导入解决方案对象)。

在开始构建 Voice Schema 之前,您必须创建一个设备来代表 BitVoicer Server 中的 Arduino。创建一个混合设备并将其命名为 ArduinoUnoWiFi。在“通信”选项卡中,选择 TCP/IP 并输入在步骤 3 中分配给 WiFi 模块的 IP 地址。在“提示”选项卡中,启用激活期开始激活期结束 线索。为两个提示选择 Int16 SendData 命令,并选择 ArduinoUnoWiFi 设备作为命令的目标。在数据字段中,为激活期的开始输入 1 提示和 0 表示激活期结束 提示。每次识别到激活词时,这些提示都会使 Arduino 打开一个 LED。当激活的时间段(在语音架构中定义)到期时,该 LED 将关闭。

现在让我们构建语音架构。虽然机器人只有 40 个基本命令,但您可能想要创建许多触发相同命令的单词组合。例如,您可能希望句子“向前一米”和“向前一米”触发相同的命令。此外,您可能希望创建复杂的命令,如“做一个方块”,它将依次触发一系列临时命令。因此,您的 Voice Schema 可以增长很多,并且拥有超过 40 个基本命令。 BitVoicer Server 支持无限句子,因此您可以根据需要定义任意数量的句子(我的最终有 80 多个句子)。这里我想给两个提示:在BitVoicer服务器管理器选项中创建一个默认命令;并将重复的命令从一个句子复制并粘贴到其他句子中。

语句命令将发送字节 Arduino 的数据类型。使用草图开头定义的常量来了解每个命令必须发送的值。复杂的命令将按顺序发送许多值,您必须控制它们之间的间隔(延迟),以便在执行前一个命令时不发送任何值。使用延迟字段设置命令之间的间隔。

解决方案对象文件 :

设备.sof

VoiceSchema.sof

第 7 步:结论

现在您所要做的就是放入 AA 电池并将 9V 电池连接到 Arduino 电源插孔,让您的机器人栩栩如生!将代码上传到 Arduino 后,不要忘记将安装在 Sparkfun 盾上的开关转到 UART 位置。否则,WiFi 模块将不会收到 Arduino 串口发送的任何数据。

打开机器人后,状态 LED 将需要一段时间才会亮起。您将看到 WiFi 模块开始通信,当 TCP/IP 连接建立时,模块 LED 之一将常亮。片刻之后,四个状态 LED 中的三个也会亮起。这意味着已经为 Arduino 分配了一个语音识别引擎。从现在开始,机器人已经准备好接受命令了。

在对机器人进行了一些测试后,我对语音识别非常满意,尽管它不能始终识别 100% 的命令。在这方面 BitVoicer Server 真的让我感到惊讶。然而,我对机器人动作的精确度并不是很满意。为了解决这个问题,我必须在车轮上添加旋转传感器。我在机器人中使用的底盘套件已经带有可以连接到齿轮的解码器磁盘。将传感器应用于这些磁盘将允许我根据实际行进距离移动机器人,使其移动更加精确。我还可以添加超声波传感器以避免在我的家具周围碰撞。我可能有一天会这样做,但现在,我把它留给你。

下次见!


代码

  • WiFi 模块设置
  • 机器人源代码
WiFi 模块设置Arduino
使用 Arduino 串口配置 Microchip WiFi RN171VX 模块。
void setup() { Serial.begin(115200); pinMode(13,输出);延迟(5000); Serial.print("$$$");延迟(1000); Serial.println("设置 wlan auth 4");延迟(1000); Serial.println("设置无线网络短语XXXXXX");延迟(1000); Serial.println("设置 wlan ssid XXXXXX");延迟(1000); Serial.println("设置 wlan 通道 0");延迟(1000); Serial.println("set wlan join 1");延迟(1000); Serial.println("set wlan tx 0");延迟(1000); Serial.println("设置ip dhcp 0");延迟(1000); Serial.println("设置ip地址XXXXXX");延迟(1000); Serial.println("设置通信远程0");延迟(1000); Serial.println("set comm close 0");延迟(1000); Serial.println("set comm open 0");延迟(1000); Serial.println("设置通信大小为 500");延迟(1000); Serial.println("设置通信时间 50");延迟(1000); Serial.println("设置串口波特率为115200");延迟(1000); Serial.println("设置串口流量0");延迟(1000); Serial.println("保存");延迟(1000); Serial.println("退出");延迟(1000); digitalWrite(13, LOW);}void loop() { }
机器人源代码Arduino
控制机器人运动,捕获音频,管理 TCP/IP 连接并与 BitVoicer 服务器通信。
#include #include #include // 定义 Arduino 引脚将用于控制 // LED 和捕获音频#define BVS_RUNNING 2#define BVS_SRE 5#define BVS_DATA_FWD 3#define BVS_ACT_PERIOD 6#define BVSM_AUDIO_INPUT 3 // 定义将作为参数传递给 // BVSP.begin 的常量functionconst unsigned long STATUS_REQUEST_INTERVAL =2000;const unsigned long STATUS_REQUEST_TIMEOUT =1000;// 定义麦克风缓冲区的大小const int MIC_BUFFER_SIZE =64;// 初始化BVSP 类的新全局实例BVSP bvsp =// Initializes() new; BVSMic 的全局实例 classBVSMic bvsm =BVSMic();// 初始化 // DualMC33926MotorShield classDualMC33926MotorShield ms =DualMC33926MotorShield() 的新全局实例;// 创建一个缓冲区,用于从 BVSMic 读取记录的样本 // classbyte micBuffer[MIC_BUFFER_SIZE];// 创建一个全局变量,指示 // Arduino 是否连接到 BitVoicer Serverboolean connected =false;// 为电机设置定义一些常量const int SPEED_STOP =0;const int SPEED_SLOW =100;const int SPEED_NORMAL =250;const int SPEED_FAST =400;const int DIRECTION_FRONT =-1;const int DIRECTION_BACK =1;// Declares a global variables to hold the current motor speed.// The default is SPEED_NORMAL, but there are voice // commands that change this setting.int motorSpeed =SPEED_NORMAL;// Stores the command duration in millisecondsunsigned long cmdDuration =0;// Stores the time the command started runningunsigned long cmdStartTime =0;// Stores whether a command is running or notbool cmdRunning =false;// Stores the last MOVE_FORWARD command. This variable // is used only for the COME_BACK command.byte lastFwdCmd =0;// Defines some constants for command names/values// Just to make the code more readableconst byte CMD_STOP =0;const byte CMD_MOVE_FORWARD =1;const byte CMD_MOVE_FORWARD_1_CM =2;const byte CMD_MOVE_FORWARD_2_CM =3;const byte CMD_MOVE_FORWARD_5_CM =4;const byte CMD_MOVE_FORWARD_10_CM =5;const byte CMD_MOVE_FORWARD_25_CM =6;const byte CMD_MOVE_FORWARD_50_CM =7;const byte CMD_MOVE_FORWARD_1_M =8;const byte CMD_MOVE_BACKWARD =9;const byte CMD_MOVE_BACKWARD_1_CM =10;const byte CMD_MOVE_BACKWARD_2_CM =11;const byte CMD_MOVE_BACKWARD_5_CM =12;const byte CMD_MOVE_BACKWARD_10_CM =13;const byte CMD_MOVE_BACKWARD_25_CM =14;const byte CMD_MOVE_BACKWARD_50_CM =15;const byte CMD_MOVE_BACKWARD_1_M =16;const byte CMD_TURN_AROUND =17;const byte CMD_TURN_AROUND_RIGHT =18;const byte CMD_TURN_AROUND_LEFT =19;const byte CMD_DO_360 =20;const byte CMD_TURN_RIGHT =21;const byte CMD_TURN_RIGHT_10 =22;const byte C MD_TURN_RIGHT_25 =23;const byte CMD_TURN_RIGHT_45 =24;const byte CMD_TURN_LEFT =25;const byte CMD_TURN_LEFT_10 =26;const byte CMD_TURN_LEFT_25 =27;const byte CMD_TURN_LEFT_45 =28;const byte CMD_DO_CIRCLE =29;const byte CMD_COME_BACK =30;const byte CMD_MOVE_FORWARD_2_M =31;const byte CMD_MOVE_FORWARD_3_M =32;const byte CMD_MOVE_BACKWARD_2_M =33;const byte CMD_MOVE_BACKWARD_3_M =34;const byte CMD_SET_SPEED_SLOW =35;const byte CMD_SET_SPEED_NORMAL =36;const byte CMD_SET_SPEED_FAST =37;const byte CMD_TURN_LEFT_45_BACKWARD =38;const byte CMD_TURN_RIGHT_45_BACKWARD =39;void setup(){ // Starts serial communication at 115200 bps Serial.begin(115200); // Sets the Arduino pin modes pinMode(BVS_RUNNING, OUTPUT); pinMode(BVS_SRE, OUTPUT); pinMode(BVS_DATA_FWD, OUTPUT); pinMode(BVS_ACT_PERIOD, OUTPUT); AllLEDsOff(); // Sets the Arduino serial port that will be used for // communication, how long it will take before a status request // times out and how often status requests should be sent to // BitVoicer Server bvsp.begin(Serial, STATUS_REQUEST_TIMEOUT, STATUS_REQUEST_INTERVAL); // Sets the function that will handle the frameReceived // event bvsp.frameReceived =BVSP_frameReceived; // Prepares the BVSMic class timer bvsm.begin(); // Prepares the motor shield class (pins and timer1) ms.init();}void loop() { // If it is not connected to the server, opens a TCP/IP // connection, sets connected to true and resets the BVSP // class if (!connected) { Connect(Serial); connected =true; bvsp.reset(); } // Checks if the status request interval has elapsed and if it // has, sends a status request to BitVoicer Server bvsp.keepAlive(); // Checks if there is data available at the serial port buffer // and processes its content according to the specifications // of the BitVoicer Server Protocol bvsp.receive(); // Gets the respective status from the BVSP class and sets // the LEDs on or off digitalWrite(BVS_RUNNING, bvsp.isBVSRunning()); digitalWrite(BVS_DATA_FWD, bvsp.isDataFwdRunning()); // Checks if there is a SRE assigned to the Arduino if (bvsp.isSREAvailable()) { // Turns on the SRE available LED digitalWrite(BVS_SRE, HIGH); // If the BVSMic class is not recording, sets up the audio // input and starts recording if (!bvsm.isRecording) { bvsm.setAudioInput(BVSM_AUDIO_INPUT, EXTERNAL); bvsm.startRecording(); } // Checks if the BVSMic class has available samples if (bvsm.available) { // Makes sure the inbound mode is STREAM_MODE before // transmitting the stream if (bvsp.inboundMode ==FRAMED_MODE) bvsp.setInboundMode(STREAM_MODE); // 从 BVSMic 类中读取音频样本 int bytesRead =bvsm.read(micBuffer, MIC_BUFFER_SIZE); // 将音频流发送到 BitVoicer Server bvsp.sendStream(micBuffer, bytesRead); } } else { // There is no SRE available // Turns off the SRE and ACT_PERIOD LEDs digitalWrite(BVS_SRE, LOW); digitalWrite(BVS_ACT_PERIOD, LOW); // If the BVSMic class is recording, stops it if (bvsm.isRecording) bvsm.stopRecording(); } // If the status has timed out, the connection is considered // lost if (bvsp.hasStatusTimedOut()) { // If the BVSMic is recording, stops it if (bvsm.isRecording) bvsm.stopRecording(); // Closes the TCP/IP connection Disconnect(Serial); AllLEDsOff(); connected =false; } // If a command is running, checks if its duration has // expired. If it has, stop the motors. if (cmdRunning) if (millis() - cmdStartTime>=cmdDuration) RunCommand(CMD_STOP);}// Handles the frameReceived eventvoid BVSP_frameReceived(byte dataType, int payloadSize){ // Performs the appropriate actions based on the frame // data type. If the data type is byte, it is a command. // If the data type is int, changes the activated // period LED. switch (dataType) { case DATA_TYPE_BYTE:RunCommand(bvsp.getReceivedByte());休息; case DATA_TYPE_INT16:digitalWrite(BVS_ACT_PERIOD, bvsp.getReceivedInt16());休息; }}// Runs the command received from the servervoid RunCommand(byte cmd){ switch (cmd) { case CMD_STOP:ms.setSpeeds(SPEED_STOP, SPEED_STOP); cmdRunning =false;返回; case CMD_MOVE_FORWARD:lastFwdCmd =cmd; ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_FRONT); cmdDuration =60000;休息; case CMD_MOVE_FORWARD_1_CM:lastFwdCmd =cmd; ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_FRONT); cmdDuration =23;休息; case CMD_MOVE_FORWARD_2_CM:lastFwdCmd =cmd; ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_FRONT); cmdDuration =47;休息; case CMD_MOVE_FORWARD_5_CM:lastFwdCmd =cmd; ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_FRONT); cmdDuration =117;休息; case CMD_MOVE_FORWARD_10_CM:lastFwdCmd =cmd; ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_FRONT); cmdDuration =234;休息; case CMD_MOVE_FORWARD_25_CM:lastFwdCmd =cmd; ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_FRONT); cmdDuration =468;休息; case CMD_MOVE_FORWARD_50_CM:lastFwdCmd =cmd; ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_FRONT); cmdDuration =1170;休息; case CMD_MOVE_FORWARD_1_M:lastFwdCmd =cmd; ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_FRONT); cmdDuration =2339;休息; case CMD_MOVE_FORWARD_2_M:lastFwdCmd =cmd; ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_FRONT); cmdDuration =4678;休息; case CMD_MOVE_FORWARD_3_M:lastFwdCmd =cmd; ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_FRONT); cmdDuration =7018;休息; case CMD_MOVE_BACKWARD:ms.setSpeeds( motorSpeed * DIRECTION_BACK, motorSpeed * DIRECTION_BACK); cmdDuration =60000;休息; case CMD_MOVE_BACKWARD_1_CM:ms.setSpeeds( motorSpeed * DIRECTION_BACK, motorSpeed * DIRECTION_BACK); cmdDuration =23;休息; case CMD_MOVE_BACKWARD_2_CM:ms.setSpeeds( motorSpeed * DIRECTION_BACK, motorSpeed * DIRECTION_BACK); cmdDuration =47;休息; case CMD_MOVE_BACKWARD_5_CM:ms.setSpeeds( motorSpeed * DIRECTION_BACK, motorSpeed * DIRECTION_BACK); cmdDuration =117;休息; case CMD_MOVE_BACKWARD_10_CM:ms.setSpeeds( motorSpeed * DIRECTION_BACK, motorSpeed * DIRECTION_BACK); cmdDuration =234;休息; case CMD_MOVE_BACKWARD_25_CM:ms.setSpeeds( motorSpeed * DIRECTION_BACK, motorSpeed * DIRECTION_BACK); cmdDuration =468;休息; case CMD_MOVE_BACKWARD_50_CM:ms.setSpeeds( motorSpeed * DIRECTION_BACK, motorSpeed * DIRECTION_BACK); cmdDuration =1170;休息; case CMD_MOVE_BACKWARD_1_M:ms.setSpeeds( motorSpeed * DIRECTION_BACK, motorSpeed * DIRECTION_BACK); cmdDuration =2339;休息; case CMD_MOVE_BACKWARD_2_M:ms.setSpeeds( motorSpeed * DIRECTION_BACK, motorSpeed * DIRECTION_BACK); cmdDuration =4678;休息; case CMD_MOVE_BACKWARD_3_M:ms.setSpeeds( motorSpeed * DIRECTION_BACK, motorSpeed * DIRECTION_BACK); cmdDuration =7017;休息; case CMD_TURN_AROUND:ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_BACK); cmdDuration =540;休息; case CMD_TURN_AROUND_RIGHT:ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_BACK); cmdDuration =540;休息; case CMD_TURN_AROUND_LEFT:ms.setSpeeds( motorSpeed * DIRECTION_BACK, motorSpeed * DIRECTION_FRONT); cmdDuration =540;休息; case CMD_DO_360:ms.setSpeeds( motorSpeed * DIRECTION_FRONT, motorSpeed * DIRECTION_BACK); cmdDuration =1065;休息; case CMD_TURN_RIGHT:ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0); cmdDuration =503;休息; case CMD_TURN_RIGHT_10:ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0); cmdDuration =56;休息; case CMD_TURN_RIGHT_25:ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0); cmdDuration =140;休息; case CMD_TURN_RIGHT_45:ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0); cmdDuration =252;休息; case CMD_TURN_LEFT:ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT); cmdDuration =503;休息; case CMD_TURN_LEFT_10:ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT); cmdDuration =56;休息; case CMD_TURN_LEFT_25:ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT); cmdDuration =140;休息; case CMD_TURN_LEFT_45:ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT); cmdDuration =252;休息; case CMD_DO_CIRCLE:ms.setSpeeds( SPEED_NORMAL * DIRECTION_FRONT, SPEED_NORMAL * DIRECTION_FRONT * 0.60); cmdDuration =4587;休息; case CMD_COME_BACK:RunCommand(lastFwdCmd);返回; case CMD_SET_SPEED_SLOW:motorSpeed =SPEED_SLOW;返回; case CMD_SET_SPEED_NORMAL:motorSpeed =SPEED_NORMAL;返回; case CMD_SET_SPEED_FAST:motorSpeed =SPEED_FAST;返回; case CMD_TURN_LEFT_45_BACKWARD:ms.setSpeeds(motorSpeed * DIRECTION_BACK, 0); cmdDuration =252;休息; case CMD_TURN_RIGHT_45_BACKWARD:ms.setSpeeds(0, motorSpeed * DIRECTION_BACK); cmdDuration =252;休息; } // Sets the command start time cmdStartTime =millis(); // Sets cmdRunning to true cmdRunning =true;}// Opens a TCP/IP connection with the BitVoicer Servervoid Connect(HardwareSerial &serialPort){ serialPort.print("$$$");延迟(500); // Use the IP address of the server and the TCP port set // in the server properties serialPort.println("open 192.168.0.11 4194");延迟(1000); serialPort.println("exit"); delay(500);}// Closes the TCP/IP connection with the BitVoicer Servervoid Disconnect(HardwareSerial &serialPort){ serialPort.print("$$$");延迟(500); serialPort.println("close");延迟(1000); serialPort.println("exit"); delay(500);}// Turns all LEDs offvoid AllLEDsOff(){ digitalWrite(BVS_RUNNING, LOW); digitalWrite(BVS_SRE, LOW); digitalWrite(BVS_DATA_FWD, LOW); digitalWrite(BVS_ACT_PERIOD, LOW);}

示意图


制造工艺

  1. 通过蓝牙控制的树莓派机器人
  2. 使用 Arduino 和 Raspberry Pi 构建您的 Internet 控制的视频流机器人
  3. 使用 Arduino 和 RFID 和 Python 的考勤系统
  4. NeoPixel Ring 的陀螺仪乐趣
  5. 使用 Raspberry Motor Shield 的 Android 控制玩具
  6. 带伺服电机的机器人避障
  7. 使用 Arduino 和 Android 设备控制 Roomba 机器人
  8. Nunchuk 控制机械臂(使用 Arduino)
  9. 语音控制机器人
  10. 带有 OK Google 的蓝牙语音控制设备
  11. 使用 Arduino 进行语音识别和合成
  12. Arduino 控制的钢琴机器人:PiBot