使用 Intel® Edison 模块构建机器人平台
本文将探讨DFRobot在DFRobot.com上提供的机器人领域令人兴奋的新产品。
获取全新的英特尔® 物联网开发套件,一个完整的硬件和软件解决方案,让开发人员能够使用英特尔® Galileo 和英特尔® Edison 开发板创建令人兴奋的新解决方案。请访问英特尔® 物联网开发人员专区。
引言
说到爱好,现在似乎是进入机器人领域最好的时机。由于基本零件的经济实惠、各种微控制器平台的多样选择以及丰富的在线论坛支持,构建一个可工作的机器人对于任何有兴趣和热情让事物活起来的人来说都触手可及。本文将探讨DFRobot* 在DFRobot.com上提供的机器人领域令人兴奋的新产品。该产品被称为“Devastator”,被宣传为机器人移动坦克平台,非常适合基本功能,例如移动和检测物体。它还提供高级功能,例如拍摄照片并自动上传到云端!添加英特尔® Edison 模块是该设备大脑的绝佳选择,它提供了分析图像、通过蓝牙*进行远程控制甚至使用Wi-Fi*连接到互联网所需的处理能力。
Devastator 机器人的组装
在开始之前,请务必检查并熟悉所有零件,并计划好两到三个小时来完成此项目。在线说明相当简单,但需要一些专注力。
所需零件
- 一把2-4毫米的十字头和一字头螺丝刀。
- 一把活动扳手或尖嘴钳。
首先从https://www.dfrobot.com/下载 Devastator 说明(搜索 Devastator)。选择 Edison 版本。截至本文撰写之时,零件号为 #ROB0125。
组装完成后,您将通过这个业余级别的项目更深入地了解基本的机器人构建。最终,您将熟悉如何将车轴、车轮、电子设备和两种不同类型的电机组装到通用坦克底盘上。
从车轴开始,然后将两个直流电机连接到履带驱动链轮。在需要让履带与地面接触之前,不要安装履带(链节)。您会希望在第一次开出去之前在车间进行几次测试。在将车轴连接到底座时,请务必提供建议的一厘米间隙。说明中提到了这一点。
接下来,将电池组和主板安装到基板上。重要的是要使用提供的塑料垫片,以防止任何焊点接触金属,否则会导致接地,并可能永久损坏电路。请自行接地,或者只是使用常识并小心处理主板。
最后,连接所有电路,准备进行实验台测试。记下您在构建过程中连接的引脚。请记住,对于 Romeo 板,硬件 PWM(脉冲宽度调制)引脚是 3、5、6 和 9。在完成之前,一个不错的做法是在一些开放的引线上缠绕电工胶带,例如图中所示的直流电机上的接线柱。另一个建议是将电线捆绑在一起,确保没有开放的电线与板子接地。
下表总结了我为此项目选择的引脚排列。PWM 引脚已突出显示;3、5、6 和 9。
引脚 | 数字 GPIO 连接 |
2 | 存在红外 |
3 | 炮塔底座旋转伺服电机 |
4 | 超声波测距仪(复合) |
5 | 炮塔顶部倾斜伺服电机 |
6 | 蜂鸣器 |
7 | 左侧 LED 灯 |
8 | 右侧 LED 灯 |
9 | 超声波测距仪(Vcc、Gnd、PWM) |
10 | 开放 |
11 | 开放 |
12 | 开放 |
13 | 开放 |
此时,您可以选择是否继续支持摄像头和距离检测。顶板可以用四个 M4 螺栓/螺母组合固定,或者您可以继续构建顶部炮塔,它也被称为六角底座旋转套件。这个顶部部件是底座伺服的基础,并允许顶部炮塔和连接的传感器(摄像头和距离检测器)旋转。六足机器人(hexapod)的构建应该不到半小时。
建造顶部炮塔(六足机器人)
在炮塔的建造过程中,请务必不要将螺钉拧得太深,以免接触到伺服电机。底座和顶部伺服电机的设计使得这成为一个常见的错误。再次强调,请熟悉坦克的整体结构,以确保您了解所有工作部件。在封闭所有东西之前,仔细检查接线是否连接正确。如果选择使用顶部炮塔,建议利用额外的电源输入插孔。这样做将有助于稳定伺服电机引起的额外功耗以及使用 Wi-Fi 无线电时增加的功率突发需求。
机器人基础知识
在让机器人开始运行之前,让我们回顾一些基础知识,以帮助您更好地了解其内部结构,并巩固对机器人所涉及电子设备的基本理解。
电压和电流
微控制器和配套组件通常额定工作电压为 5.0 伏或 3.3 伏,电流小于 1 安培。电压代表在任何给定时间可用于设备的潜在能量。在处理电子设备时,了解电压和电流的区别非常重要,以避免潜在地损坏设备。
虽然微控制器板的输入电压可能列为 9-12 伏或更高,但连接到板子的每个组件的工作电压和最大电压额定值要低得多。板上的降压转换器用于将电压水平降低到安全水平。施加超过设备额定电压的电压会导致设备烧毁并可能永久损坏。英特尔® Edison 模块的 Romeo 板已配备降压电压转换器。更多信息可以在维基百科*上轻松找到:https://en.wikipedia.org/wiki/Voltage_regulator_module
电压代表潜在能量的大小,而电流则代表在任何给定时间实际流过设备的电量。您可能听说过这样一句话:“不是电压,而是电流会杀死你”。电压根据定义,只是源(例如墙壁插座或电池)可用能量的潜力。只有当电路形成时,实际的电流才开始流动,并且始终以由第三个因素(称为电阻)控制的流速流动。
电路最常用的介质是铜线,一英寸长的铜线电阻极低,约为 8.82e-6 欧姆。相比之下,在最极端条件下(潮湿),人体的电阻为 1000 欧姆。在大约 0.01A(1 毫安)时,您会感受到电力的影响,10 毫安时可能会发生肌肉收缩。由于大多数微控制器将电压限制在 20 伏以下,因此在这些低电流水平下工作没有安全问题。
耗电
所有组件都会根据其运行需要消耗(汲取)尽可能多的电流。对于电机,随着负载的增加,电流需求也会增加。因此,直流电机尤其需要额外的电源,其电压高于LED或传感器等其他组件。使用直流电机时,务必提供适当的电机控制器和二极管保护,以避免电机开关时产生的反电动势。有关这些主题的更多详细信息,可以通过搜索“直流电机”和“反电动势”在线找到。
常见电压和电流范围示例
设备/组件 | 直流电压 | 最小/最大电流 |
Intel® Edison 模块 | 7V-15V | 1A输入 |
200mA 消耗(Wi-Fi 突发期间 600mA) | ||
英特尔® 爱迪生 GPIO 引脚 @3.3v | 1.8-3v输出 | 24毫安 |
英特尔® 爱迪生 GPIO 引脚 @5v | 1.8-3v输出 | 32毫安 |
普通 LED | 1.8-4伏 | 20毫安 |
直流有刷电机 | 6V-9V | 取决于堵转电流 |
执行器
执行器是可以由微控制器控制的东西。一些例子是电机、LED 和蜂鸣器。这些组件的控制方式因设备类型而异。例如,LED 可以通过连接到 GPIO 引脚并结合限流电阻来打开和关闭。简单地让电流流过二极管会使其发光。电流越大,光线越亮。然而,电机最好使用一种称为脉冲宽度调制 (PWM) 的技术来控制,它以非常快的速度以开/关方式切换电机的电压。
PWM 基础知识
直流电机并非由连续的电流供电。它采用一种称为脉冲宽度调制 (PWM) 的技术供电,该技术允许电流以非常快的速度开启和关闭。当使用 PWM 时,电机的开启时间由底层信号(以特定频率振荡)和称为“占空比”(信号在波形振荡期间保持高电平(开启)的时间量)的组合控制。如果已知基于硬件的定时器提供 1Hz(每秒一次)的频率,则可以通过将占空比设置为 0.5 来使灯闪烁,这意味着灯亮半秒,灭半秒。同样,通过让信号保持高电平一整秒,灯可以看起来闪烁得更慢。
伺服电机
与直流电机类似,伺服电机以完全相同的方式运行,但增加了能够精确定位以在给定位置停止和保持的能力。这里有关于伺服电机的一个很好的介绍:伺服电机简介
传感器
增加检测物体存在以及其距离的能力将使任何机器人变得更智能。使用标准GPIO引脚,PIR(被动红外)可用于检测电磁场的变化。由于所有物体都发射辐射,这种敏感设备甚至能够检测到光线的微小变化。https://en.wikipedia.org/wiki/Passive_infrared_sensor
另一个优秀的传感器示例是超声波测距仪,它是一种距离指示器。该传感器利用超声波通过向物体发射声波并检测其返回所需的时间来确定物体的距离。这类似于警察雷达测速仪使用的老式雷达,但不同之处在于它使用声波而非无线电波。该设备价格实惠,但仅适用于在相对干净的条件下(即没有灰尘、污垢或雪)进行短距离计算。
英特尔® 爱迪生模块的 Romeo 板概览
Devastator 机器人的大脑,包括移动电机、感知周围环境和切换灯光的能力,都由 Romeo 开发板提供。该平台配备了十四个 GPIO 引脚(4 个 PWM)、内置 H 桥电机驱动器、SPI 和 I2C 功能、专用外部电源连接以及英特尔® 爱迪生模块,有望成为一个功能强大的开发板,可为任何入门级移动机器人项目提供动力。该平台的美妙之处在于其可扩展性。额外的电源和组件可以轻松地添加到坚固的底盘上并进行安装。有关更多信息,请访问DFRobot.com以下载 Romeo 板的完整原理图。
幂
DFRobot* Devastator 套件附带的标准电池组是 6 节 1.5V AA 电池组,总电源电压为 9V。最大输入电压能够支持高达 12V 的输入,以提供额外电力。重要的是要记住,虽然可以提供额外的电压作为输入,但主板本身在任何给定时间都会在 GPIO 引脚上提供 3.3V,并为电机控制器电路提供单独的受控电压。一个标记为“伺服电源”的单独电源插孔可以连接以提供额外的伺服控制电源。虽然整个平台将仅依靠提供的 9V(AA x 6)电池组运行,但您会发现并行操作,如直流电机定向移动、伺服摇摄和 Wi-Fi 上传突发,将需要几乎全部 9V 的电力。仅直流电机驱动器本身在全源下每个电机将使用 2A 的恒定电流。预先了解这些情况,强烈建议投资购买可充电电池。坦克在全速运行几次后,额定 2,500 毫安时的 AA 标准碱性电池将迅速耗尽。一个不错的补充是购买一套 9V 可充电电池,并提供稳定的 18V 输入。此外,伺服插孔的独立输入电源是一个不错的选择,可以为板子提供额外的电源,并减轻主输入的电流消耗。如果选择连接伺服输入,请务必不要超过伺服电机和连接设备的输入电压。
电机控制
直流电机连接在电源输入插孔旁边,并如图所示,直接连接到H桥驱动器IC,该IC执行前进和后退运动所需的电压偏置。虽然英特尔® 爱迪生模块是电路板的主控制器,但电机控制器IC实际上由Atmel ATMega8 MCU驱动。另外,伺服电机连接到GPIO轨道的PWM专用引脚,并使用典型的伺服控制时序信号驱动。如前一节所述,如果您选择向伺服输入提供额外电压,请务必不要超过伺服电机可以处理的输入电压。
数据和串口连接
板子输入电源的另一侧是微型 USB 连接。您最可能使用的第一个连接是串口连接,标有 COM。此端口将提供连接到英特尔® 爱迪生模块并运行终端 shell 会话的功能,以执行诸如配置爱迪生、连接 Wi-Fi,甚至在 shell 中配置和下载额外软件组件等操作。它不用于数据传输。第二个连接是 USB/OTG 连接,这是将 Arduino* 风格草图上传到板子时使用的主要连接。一个建议是,在工作台上测试时,将电缆连接好并从计算机上拔下。与任何物理连接一样,过多的插拔会增加磨损输入端口的风险。您会发现在测试的初始步骤中会有大量的连接和断开,所以最好在连接到 PC 的“A”端而不是板子上的微型端进行操作。
此时值得一提的另一个连接是 FTDI 连接。您需要更新板上的 ATMega8 固件,以解决与 I2C 稳定性相关的已知问题。此更新对于确保您的直流电机正常运行是必要的,将在下一节中介绍。
固件编码
要让事情真正奏效,您必须创建软件并将其上传到英特尔® Edison 模块。
首先,由于英特尔® Edison 模块运行 Linux* 操作系统 (Yocto Linux),一种方法是简单地编写 C、C++ 或 Python* 程序,并直接在操作系统中执行,就像任何其他在任何 Linux 操作系统中运行的应用程序一样。社区中已经有许多库可用于访问英特尔® Edison 模块上的所有硬件。从简单的 GPIO 引脚访问到 Wi-Fi 和蓝牙,都有免费可用的库供您安装和编程。您可以简单地创建程序,并执行标准的 make 过程来创建可执行文件。
编程 Edison 的第二种方法,也是本文描述的方法,是使用众所周知的 Arduino* 库和 IDE。使用 Arduino 进行编程很简单,并通过在 Linux 操作系统中作为服务运行的 CLLoader Arduino 模拟器在 Intel® Edison 模块上完成。此服务默认设置为在 Intel® Edison 模块上运行,因此上传和运行 Arduino 草图不需要额外的操作。只需连接您的开发板并上传草图,就像任何其他 Arduino 兼容的 MCU 平台一样。您可以使用 Linux shell 中的简单 ps 命令验证 clloader 进程是否正在运行。
要开始使用 Arduino 进行编程,请从https://www.arduino.cc/en/Main/Software下载最新版 Arduino IDE
最后,最新的 Intel XDK® 提供了通过 Wi-Fi 上传草图的能力。XDK 使用的开发语言是 Node JavaScript* (Node.JS*),并且可用库和封装器不断增长。应用程序以与 Arduino 草图类似的方式编译并上传到直接在 Intel® Edison 模块上运行的守护进程中,但通过不同的服务。
安装
在进行任何外设测试之前,最好先确保所有固件都已更新且驱动程序已安装。连接 COM 端口(不是 OTG 端口),并确保它在串行 COM 端口上可见且波特率正确,方法是在 Windows* 上执行“设备管理器”并导航到端口。该连接是默认的串行连接,可用于远程连接到设备并运行 Linux shell 会话。
接下来,连接数据OTG 连接。此连接是草图和代码更新到英特尔® Edison 模块的方式。
下载英特尔® 爱迪生模块相关软件
驱动程序和设置
https://software.intel.com/en-us/iot/hardware/edison/downloads
固件烧录工具
https://software.intel.com/en-us/using-flash-tool-lite
最后,下载最新的 Poky 镜像并运行烧录工具,用最新的 Linux 镜像更新英特尔® Edison 模块。
https://software.intel.com/en-us/iot/hardware/edison/downloads
通过 FTDI 连接更新 ATMega8* MCU
此更新是必需的,以确保您的 ATMega8 完全是最新的,特别是要修复导致电机出现问题的 I2C 缺陷!
https://www.dfrobot.com/wiki/index.php/Romeo_for_Edison_Controller_SKU:_DFR0350#Atmega8_Firmware_Upgrade
配置英特尔® Edison 模块
使用 PuTTY,以与端口上识别的相同串口设置连接,并以“root”身份通过 ssh 连接,无需密码。请务必按 Enter 键完成连接。
从此处下载 PuTTY:http://www.putty.org/
运行 'configure-edison -setup',并按照提示完成设置。如果可用,您可以选择连接到 Wi-Fi。
更新英特尔® Edison 模块以允许草图在启动时加载
当前 Poky 镜像发行版未正确设置默认脚本加载程序的加载程序权限。此过程是强制性的,以确保在设备下次启动时执行最后上传的镜像。需要上传四个文件。
下载更新文件
https://github.com/gameswarp/edison-clloader
备份您当前的文件,然后使用 WinSCP 将下载的文件传输到 /opt/edison 文件夹。
下载 WinSCP: https://winscp.net/eng/download.php
文件上传后,选择新文件,然后按 F9 将这四个文件更改为可执行文件。
您可以通过运行 diff 命令来验证新上传的脚本是否不同,或者只是手动验证更改。
有关此过程的更多详细信息可在此处找到:https://communities.intel.com/thread/77945
导入 Arduino* 库
Arduino 基础知识包括连接和识别设备、确保安装正确的板卡驱动程序和库,以及下载并安装任何通用库支持到正确的位置。
添加库支持就像找到代码并将文件夹和文件复制到您的 _Arduino\library_ 文件夹一样简单。Arduino IDE 也有一个“导入为 Zip”选项,但如果库提供者没有遵循所有正确的流程和结构,有时这个过程可能不起作用。最重要的是,将库添加到 Arduino 就像将文件夹放在 libraries 文件夹下一样简单。您还会发现大多数库都带有一个 examples 子文件夹,在下次启动 Arduino IDE 时,它们会很好地显示在您的 examples 下拉菜单中。有关更多信息,您可以参考以下链接:https://www.arduino.cc/en/Reference/Libraries
设置 Arduino IDE
步骤 1: 确保 Arduino IDE 已安装英特尔® Edison 模块 i686 板支持。在安装最新版 Arduino 并遵循英特尔® Edison 模块设置安装程序后,此功能应该已经可用。
确保已安装英特尔® 爱迪生模块 i696 板支持:[工具--►开发板--►开发板管理器]
步骤 2: 安装 DFRobot 库
https://github.com/ouki-wang/Devastator-Tank-Mobile-Platform-with-Edison
将 DevastatorEdison 文件夹复制到您的 Arduino 库文件夹中
[草图--►包含库--►管理库]。
搜索 DFRobot,然后点击安装按钮。
步骤 3:运行快速测试
为了验证 DFRobot 库支持是否可用,请创建一个快速草图并引用库提供的类。如果以下代码能够编译,则您已准备好开始设备的预发布测试。如果代码无法编译,请尝试重新启动 Arduino IDE 或手动验证库是否已正确安装。
#include <DFRobot.h>
#include <IIC1.h>
DFrobotEdison leftMotor;
void setup() {}
void loop() {}
预发布测试
在发布 Devastator 机器人进行测试之前,建议编写一组基本的裸机测试,以确保功能正确。预先进行这项稳定化工作将使您能够及早发现缺陷,并缩短未来功能开发的周转时间。
基本测试
- 控制电机 - 前进、后退、左转和右转
- 开灯
- 蜂鸣器发声
- 物体检测
总的来说,请务必缓慢地进行测试,并且在验证了较小的操作范围之前,切勿全速或大角度运行电机。对于这个项目,一组好的测试用例将包括确保每个组件都正常运行。添加 `Serial.print()` 命令以将预期行为输出到控制台进行日志记录非常有帮助。再次强调,预先完成所有这些工作将提高您将其带入环境之前的信心。DFRobot 套件中提供的一个盒子(电器配件盒)是一个很好的底座,为 DFRobot 在有无履带连接的预发布测试提供了充足的车轮间隙。
API 示例
IsObjectDetected()
SoundBuzzer()
FlashLights()
StopMotors()
TurnLeft()
TurnRight()
SetDirection()
GoStraight()
TurnAround()
Backup()
StartupWarning()
传感器测试
/*
* This example will test the following items:
* - PIR Sensor
* - Left and Right LEDs
* - Buzzer
* OVERVIEW:
* On Presence, flash lights and emit tone.
* Tone should change each time PIR is triggered
*
* Matt Chandler
* Intel, Corp.
* December 2016
*/
byte presencePin = 2;
byte leftLED = 7;
byte rightLED = 8;
byte buzzerPin = 6;
bool buzzerOn=true;
void setup() {
pinMode(presencePin, INPUT);
pinMode(leftLED, OUTPUT);
pinMode(rightLED, OUTPUT);
pinMode(buzzerPin, OUTPUT);
Serial.begin(9600);
}
void loop(){
if (IsObjectDetected())
{
flashLights();
soundBuzzer();
}
}
bool IsObjectDetected()
{
return digitalRead(presencePin)==1 ? true:false;
}
void soundBuzzer()
{
if (!buzzerOn)
return;
int delay=200;
unsigned int buzzerTone = 100;
for(int i=0;i<4;i++)
{
tone(buzzerPin, buzzerTone, delay);
}
noTone(buzzerPin);
}
void flashLights()
{
digitalWrite(leftLED,1);
delay(200);
digitalWrite(leftLED,0);
delay(500);
digitalWrite(rightLED,1);
delay(200);
digitalWrite(rightLED,0);
}
电机测试
/*
* Sample DFRobot Motor Tests
*
* goStraight(), turnLeft(), turnRight(), stopMotors()
*
* Matt Chandler
* Intel, Corp.
* December, 2016
*/
#include <DFRobot.h>
#include <IIC1.h>
DFrobotEdison leftMotor;
DFrobotEdison rightMotor;
bool directionToggle = false;
byte currentSpeedRight = 0;
byte currentSpeedLeft = 0;
byte leftLED = 7;
byte rightLED = 8;
byte DIRECTION_LEFT = 0;
byte DIRECTION_RIGHT = 1;
byte startupDelaySeconds = 5;
void setup() {
leftMotor.begin(M2);
rightMotor.begin(M1);
pinMode(leftLED, OUTPUT);
pinMode(rightLED, OUTPUT);
Serial.begin(9600);
}
void loop(){
startupWarning();
goStraight(150, 2);//speed, distance
turnLeft(45, 2);
goStraight(150, 2);//speed, distance
turnRight(45, 2);
goStraight(150, 2);//speed, distance
stopMotors();
backup(150,2);
}
void startupWarning()
{
stopMotors();
Serial.println("");
Serial.print("Getting ready in ");
Serial.print(startupDelaySeconds);
Serial.println(" seconds");
for (int i=startupDelaySeconds; i > 0; i--)
{
Serial.print(" ");
Serial.print(i);
digitalWrite(leftLED,1);
digitalWrite(rightLED,1);
delay(500);
digitalWrite(leftLED,0);
digitalWrite(rightLED,0);
delay(500);
}
Serial.println("");
Serial.println("GO!!");
}
void setDirection(const uint8_t dir)
{
leftMotor.setDirection(dir);
rightMotor.setDirection(dir);
}
void goStraight(byte speed)
{
stopMotors();
setDirection(ANTICLOCKWISE);
leftMotor.setSpeed(speed);
rightMotor.setSpeed(speed);
}
void stopMotors()
{
leftMotor.stop();
rightMotor.stop();
delay(1000);
}
void goStraight(byte speed, int durationSeconds)
{
Serial.println(" ");
Serial.println("Going straight");
currentSpeedRight = speed;
currentSpeedLeft = speed;
delay(500);
goStraight(speed);
delay(durationSeconds*1000);
}
void backup(byte speed, int durationSeconds)
{
stopMotors();
setDirection(CLOCKWISE);
leftMotor.setSpeed(speed);
rightMotor.setSpeed(speed);
delay(durationSeconds*1000);
}
void turnLeft(byte angle, int durationSeconds)
{
turn(DIRECTION_LEFT, angle, durationSeconds*1000);
}
void turnRight(byte angle, int durationSeconds)
{
turn(DIRECTION_RIGHT, angle, durationSeconds*1000);
}
void turn(byte direction, byte angle, byte durationMS)
{
DFrobotEdison motor;
String directionText;
byte directionPin;
//Ensure going straight first
byte currentSpeed = currentSpeedLeft = currentSpeedRight;
if (direction == DIRECTION_LEFT)
{
directionText = "Left";
motor = leftMotor;
directionPin = leftLED;
}
else
{
directionText = "Right";
motor = rightMotor;
directionPin = rightLED;
}
delay(500);
digitalWrite(directionPin,1);
// Take current right speed and lower left motor by mapped value
//Convert angle to speed where 0 is straight ahead
byte newSpeed = map(angle, 0, 90, 0, currentSpeed);
Serial.print("Turning ");
Serial.print(directionText);
Serial.print(" at angle ");
Serial.print(angle);
Serial.print("Current Speed: ");
Serial.println(currentSpeed);
Serial.print("New speed: ");
Serial.println(newSpeed);
delay(250);
motor.setSpeed(newSpeed);
Serial.print("Turning ");
Serial.print(directionText);
Serial.print(" now for ");
Serial.print(durationMS/1000);
Serial.println(" seconds.");
delay(durationMS);
digitalWrite(directionPin,0);
Serial.println("");
}
上路
现在,一些基本测试已经通过,您的机器人已准备好完成建造。在开始这最后一步之前,建议上传一个空草图或一个简单的闪光测试,以避免在您打开坦克时执行任何以前的电机代码。关闭电池,然后小心地将履带连接到坦克两侧的链轮上。烧录前一节中的一个测试运动草图,断开 USB,然后将坦克放在地上。打开电池开关,开始执行草图!
这是一个非常基本的草图,它将启动您的探索。我建议在反转方向之前始终执行 motorOff() 调用,并鼓励您修改代码并从中获得乐趣。
应要求巡游
/*
* Sample DFRobot Motor and Lights test
*
* Wait for PIR Sensor detection
* Go Forward
* Turn Around 2 x 180'
* Return to position by backing up
* If object is detected in rear, attempt to go around it by altering angle
*
*
*
* Matt Chandler
* Intel, Corp.
* December, 2016
*/
#include <DFRobot.h>
#include <IIC1.h>
bool testFlag = false;
DFrobotEdison leftMotor;
DFrobotEdison rightMotor;
byte presencePin = 2;
byte leftLED = 7;
byte rightLED = 8;
bool directionToggle = false;
byte currentSpeedRight = 0;
byte currentSpeedLeft = 0;
byte DIRECTION_LEFT = 0;
byte DIRECTION_RIGHT = 1;
byte startupDelaySeconds = 5;
double turnAroundTimeSeconds = 4;
byte turnAroundSpeed = 100;
byte buzzerPin = 6;
bool buzzerOn=true;
void setup() {
leftMotor.begin(M1);
rightMotor.begin(M2);
pinMode(leftLED, OUTPUT);
pinMode(rightLED, OUTPUT);
Serial.begin(9600);
}
void loop(){
stopMotors();
if (IsObjectDetected())
{
startupWarning();
if(testFlag)
{
turnAround();
stopMotors();
}
else
{
goStraight(200, 6);//speed, distance
turnAround(); //180
goStraight(200, 2);//speed, distance
turnAround();
backup(200,8); //Go backwards
if(IsObjectDetected())
{
soundBuzzer();
backup(200,4);
Serial.println("Object Detected");
goStraight(200, 2);//speed, distance
turnLeft(45, 4);
turnRight(45, 4);
goStraight(200, 3);//speed, distance
}
turnAround();
}
}
}
void startupWarning()
{
Serial.println("");
Serial.print("Getting ready in ");
Serial.print(startupDelaySeconds);
Serial.println(" seconds");
for (int i=startupDelaySeconds; i > 0; i--)
{
Serial.print(" ");
Serial.print(i);
digitalWrite(leftLED,1);
digitalWrite(rightLED,1);
delay(500);
digitalWrite(leftLED,0);
digitalWrite(rightLED,0);
delay(500);
}
Serial.println("");
Serial.println("GO!!");
soundBuzzer();
}
void setDirection(const uint8_t dir)
{
leftMotor.setDirection(dir);
rightMotor.setDirection(dir);
}
void goStraight(byte speed)
{
stopMotors();
rightMotor.setDirection(ANTICLOCKWISE);
leftMotor.setDirection(ANTICLOCKWISE);
delay(500);
leftMotor.setSpeed(speed);
rightMotor.setSpeed(speed);
}
void backup(byte speed, int durationSeconds)
{
stopMotors();
rightMotor.setDirection(CLOCKWISE);
leftMotor.setDirection(CLOCKWISE);
leftMotor.setSpeed(speed);
rightMotor.setSpeed(speed);
delay(durationSeconds*1000);
}
void stopMotors()
{
Serial.println("Stopping motors");
leftMotor.stop();
rightMotor.stop();
delay(3000);
}
void goStraight(byte speed, int durationSeconds)
{
Serial.println(" ");
Serial.println("Going straight");
currentSpeedRight = speed;
currentSpeedLeft = speed;
goStraight(speed);
delay(durationSeconds*1000);
}
void turnLeft(byte angle, int durationSeconds)
{
turn(DIRECTION_LEFT, angle, durationSeconds*1000);
}
void turnRight(byte angle, int durationSeconds)
{
turn(DIRECTION_RIGHT, angle, durationSeconds*1000);
}
void turnAround()
{
stopMotors();
Serial.println("Turning around");
leftMotor.setDirection(CLOCKWISE);
rightMotor.setDirection(ANTICLOCKWISE);
rightMotor.setSpeed(turnAroundSpeed);
leftMotor.setSpeed(turnAroundSpeed);
delay(turnAroundTimeSeconds*1000);
stopMotors();
Serial.println("Turned around");
rightMotor.setDirection(ANTICLOCKWISE);
rightMotor.setDirection(ANTICLOCKWISE);
}
void turn(byte direction, byte angle, int durationMS)
{
if (angle==90)
{
Serial.println("Angle is 90, turning around");
turnAround();
return;
}
DFrobotEdison turningMotor;
DFrobotEdison oppositeMotor;
String directionText;
byte directionPin;
//Ensure going straight first
byte currentSpeed = currentSpeedLeft = currentSpeedRight;
if (direction == DIRECTION_LEFT)
{
directionText = "Left";
turningMotor = leftMotor;
oppositeMotor = rightMotor;
directionPin = leftLED;
}
else
{
directionText = "Right";
turningMotor = rightMotor;
oppositeMotor = leftMotor;
directionPin = rightLED;
}
delay(1000);
digitalWrite(directionPin,1);
// Take current right speed and lower left motor by mapped value
//Convert angle to speed where 0 is straight ahead
byte newSpeedOfTurningMotor = map(angle, 0, 90, 0, currentSpeed);
Serial.print("Turning ");
Serial.print(directionText);
Serial.print(" at angle ");
Serial.println(angle);
Serial.print("Current Speed: ");
Serial.println(currentSpeed);
Serial.print("New speed: ");
Serial.println(newSpeedOfTurningMotor);
delay(250);
turningMotor.setSpeed(newSpeedOfTurningMotor);
Serial.print("Turning ");
Serial.print(directionText);
Serial.print(" now for ");
Serial.print(durationMS/1000);
Serial.println(" seconds.");
delay(durationMS);
digitalWrite(directionPin,0);
Serial.println("");
turningMotor.setSpeed(currentSpeed);
oppositeMotor.setSpeed(currentSpeed);
}
bool IsObjectDetected()
{
return digitalRead(presencePin)==1 ? true:false;
}
void flashLights(byte seconds)
{
for (int i=0;i<seconds;i++)
{
digitalWrite(leftLED,1);
delay(200);
digitalWrite(leftLED,0);
delay(seconds);
digitalWrite(rightLED,1);
delay(200);
digitalWrite(rightLED,0);
}
}
void soundBuzzer()
{
if (!buzzerOn)
return;
int delay=200;
unsigned int buzzerTone = 100;
for(int i=0;i<4;i++)
{
tone(buzzerPin, buzzerTone, delay);
}
noTone(buzzerPin);
}
高级操作
现在机器人可以四处移动了,您可以通过增强 Arduino 代码库中的代码,或者扩展到前一节中提到的一些不同开发选项,从而发挥更多创意。一个开发选项是直接通过 C 开发或使用 Intel XDK® 中的 JavaScript 封装器深入研究 mraa(发音为“m-rah”)Linux 库。通过转向 Intel XDK®,您将能够无线编程设备,这是一个非常好的功能,它将消除传统 Arduino 草图上传需要连接到设备的麻烦。有关更多高级功能,包括 mraa 讨论以及 Wi-Fi 摄像头功能,请查看这些附加文章
关于作者
Matt Chandler 是英特尔的高级软件工程师,负责物联网的规模启用项目。
参考文献
Arduino* 下载
https://www.arduino.cc/en/Main/Software
DFRobot* 产品描述
https://www.dfrobot.com/wiki/index.php/Romeo_for_Edison_Controller_SKU:_DFR0350
WinSCP 下载 – 用于安全文件传输
https://winscp.net/eng/download.php
PuTTY 下载 – 用于安全地通过 shell 访问 Edison
http://www.putty.org/
被动红外检测 (PID) 传感器维基
https://en.wikipedia.org/wiki/Passive_infrared_sensor
确保草图已保存 - 修复 Poky 发行版中已知图像的缺陷,截至 2016 年 6 月
https://communities.intel.com/thread/77945
伺服电机简介
http://www.sciencebuddies.org/science-fair-projects/project_ideas/Robotics_ServoMotors.shtml
蜂鸣器代码示例
https://www.arduino.cc/en/Tutorial/ToneMelody?from=Tutorial.Tone
USB OTG 连接
https://en.wikipedia.org/wiki/USB_On-The-Go
注意事项
本文档不授予任何知识产权的许可(明示或暗示,禁止反言或以其他方式)。
英特尔不承担任何明示和暗示的担保,包括但不限于适销性、特定用途适用性和非侵权的暗示担保,以及因履行过程、交易过程或贸易惯例产生的任何担保。
本文档包含有关开发中的产品、服务和/或流程的信息。此处提供的所有信息如有更改,恕不另行通知。请联系您的英特尔代表以获取最新的预测、日程安排、规格和路线图。
所描述的产品和服务可能包含称为勘误的缺陷或错误,这可能导致与公布的规格不符。当前的已特性化勘误可应要求提供。
可通过致电 1-800-548-4725 或访问 www.intel.com/design/literature.htm 获取本文档中引用且具有订单号的文档副本。
Intel、Intel 标识和 Intel RealSense 是英特尔公司在美国和/或其他国家的商标。
*其他名称和品牌可能被声明为他方财产
**此示例源代码根据英特尔示例源代码许可协议发布。
© 2016 英特尔公司。