第 12 章 遥控机器人

最后更新于:2022-04-01 02:53:48

> **作者介绍** > > **Liz Looney** > > ![{%}](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd386f57b.png) > > Liz Looney是本书的合著者之一。她是谷歌的软件工程师,也是谷歌“机器人工作小组”(Robotics Task Force)的成员,作为App Inventor团队的初创成员,她领导了乐高头脑风暴机器人(LEGO MINDSTORMS)组件的开发工作。Liz Looney是一位卓越的软件工程师,有着超过25年的从业经历,曾先后在Borland、Oracle及Google公司工作。 本章将创建一个应用,将Android手机变成LEGO MINDSTORMS NXT 机器人的遥控器。应用中用按钮来控制机器人前后移动、左右转动和停止,如果机器人遇到障碍物,它还会自动停止。应用中使用具有蓝牙功能的手机与机器人通信。 LEGO MINDSTORMS机器人不只是玩具,更是教具。After-school program 使用机器人来教小学和初中的孩子们掌握解决问题的能力,并引导他们了解工程和计算机编程。NXT机器人也用于FIRST LEGO League 机器人竞赛,这项比赛允许9-14岁的孩子参加。 ![{%}](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd3e321ac.png) NXT可编程机器人套件中有一个“NXT智能积木”主单元,它可以控制三个电机及四个输入传感器。你可以用乐高的构造元件、齿轮、车轮、电机和传感器来组装机器人。该套件自带的软件可以对机器人进行编程,但现在我们将用App Inventor来创建Android应用,通过蓝牙连接来控制NXT机器人。 应用中参与协作的机器人具有超声波传感器以及用于移动的车轮,如Shooterbot 机器人。图中所示,这款机器人通常是人们利用LEGO MINDSTORMS NXT 2.0套件建造的第一个机器人。它的左车轮与输出端口C相连,右车轮与输出端口B相连,颜色传感器与输入端口3相连,超声波传感器与输入端口4相连。 ## **学习要点** 本章用到了以下组件和概念: * BluetoothClient组件:用于建立Android设备与NXT机器人之间的蓝牙连接; * ListPicker组件:为用户提供机器人选择列表,选中后开始建立机器人到Android的连接; * NxtDrive组件:用于驱动机器人的轮子; * NxtUltrasonicSensor组件:利用机器人的超声波传感器探测障碍物; * Notifier组件:显示错误消息。 ## **准备开始** 本章的应用需要Android 2.0或以上版本。此外,出于安全原因,蓝牙设备必须首先配对才能彼此连通。在开始构建应用之前,需要按以下步骤使Android设备与NXT机器人配对: 1\. 在NXT上单击向右箭头,直到显示“Bluetooth”,然后按下橙色方块; 2\. 点击向右的箭头,直到显示“Visibility”,然后按下橙色方块; 3\. 如果“Visibility”值已设定为可见,继续步骤4;如果不可见,请单击向左或向右箭头设置其值为可见; 4\. 在Android设备上,进入设置→无线与网络; 5\. 确保打开蓝牙功能; 6\. 点击“蓝牙”; 7\. 在“可用设备”中查找名为“NXT”的设备; 8\. 如果机器人名字下显示“已配对但未连接”字样,则配对成功!否则,继续执行步骤9; 9\. 如果机器人名字下显示“与此设备配对”,则点击它; 10\. 在NXT上,要求输入密码,按下橙色方块接受1234为密码; 11\. 在Android上,也会要求输入PIN码,输入1234,然后按确定; 12\. 现在应该看到“已配对但未连接。”,说明配对成功! > ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd43aca5c.png) 注意:如果你曾经修改过机器人的名字,则寻找机器人现在的名字,而非“NXT”。 连接到App Inventor网站,创建新项目“NXTRemoteControl”,将设置屏幕的标题为“遥控机器人”,并连接测试手机。 ## **设计组件** 在这个应用中,我们需要分别创建可见组件及不可见组件,并分别定义它们的行为。 ### **不可见组件** 在创建用户界面之前,先来创建表12-1中的不可见组件,如图12-1所示,用来控制NXT。 **表12-1 NXT“机器人遥控”应用中的不可见组件** | 组件类型 |面板中分组 | 命名 | 作用 | | --- | --- | --- | --- | | BluetoothClient| Connectivity | BluetoothClient1 |建立Android与NXT的连接 | | NxtDrive | LEGO® MINDSTORMS® | NxtDrive1 |驱动机器人的轮 | | NxtUltrasonicSensor | LEGO® MINDSTORMS® |NxtUltrasonicSensor1 | 检测障碍物 | | Notifier | User Interface | Notifier1 | 显示错误信息 | ![{%}](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd490a4db.png) **图 12-1 在组件设计器底部显示的不可见组件** 按以下方式设置组件的属性: 1\. 设置NxtDrive1及NxtUltrasonicSensor1的BluetoothClient属性为 BluetoothClient1;(说明轮子的驱动与障碍物的侦测都需要依赖蓝牙通信——译者注) 2\. 勾选NxtUltrasonicSensor1的BelowRangeEventEnabled属性(近距离侦测障碍物功能可用); 3\. 设置NxtDrive1的DriveMotors属性 * 如果机器人的左轮电机与输出端口C连接,右轮电机与输出端口B连接,则保持默认设置“CB”; * 如果机器人的配置与上述不同,则将DriveMotors属性设置为两个字母的文本,其中第一个字母是连接左轮电机的输出端口,第二个字母是连接右轮电机的输出端口。 4\. 设置NxtUltrasonicSensor1的SensorPort属性 * 如果机器人的超声波传感器与输入端口4连接,则保持默认值“4”; * 如果机器人的配置与上述不同,则将SensorPort设置为与超声波传感器连接的输入端口。 ### **可视组件** 现在创建用户界面组件,如图12-2所示。 ![{%}](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd4e979bf.png) **图 12-2 组件设计器中的应用** 建立蓝牙连接时,Android设备需要访问NXT机器人具有唯一性的蓝牙地址,但蓝牙地址由8个用冒号分隔的2位数的十六进制数(二进制数的另一种表示方式)组成,输入起来异常麻烦,而且每次运行应用都要在手机上输入该地址。为了减少麻烦,使用ListPicker来显示已经与手机配对的机器人列表(列表项的值为机器人的名称及蓝牙地址),并从中选择一个。 使用按键来驱动机器人的前进、后退、左右转动、停止和断开连接,使用VerticalArrangement来放置除ListPicker以外的所有组件,用HorizontalArrangement来放置左右转向及停车按钮。 按照表12-2中列出的组件来创建图12-2所示的用户界面。 **表12-2 NXT机器人控制器应用中的可见组件** | 组件类型 | 面板中分组 | 命名 | 作用 | | --- | --- | --- | --- | | ListPicker | User Interface | ConnectListPicker |选择要连接的机器人 | | VerticalArrangement | layout | VerticalArrangement1 |布局容器,容纳除ListPicker之外的组件 | | Button | User Interface | ForwardButton | 前进 | | HorizonalArrangement | layout | HorizonalArrangement1 |布局容器,容纳左转、右转、停止按钮 | | Button | User Interface | LeftButton | 左转 | | Button | User Interface | StopButton | 停止 | | Button | User Interface | RightButton | 右转 | | Button| User Interface | BackwardButton | 后退 | | Button | User Interface | DisconnectButton| 与NXT断开连 | 按照图12-2所示来设置可视组件布局:将LeftButton、StopButton和RightButton放在HorizontalArrangement1中,将ForwardButton、HorizontalArrangement1、BackwardButton和DisconnectButton放在VerticalArrangement1中。 按下列方式设置组件属性: 1\. 取消勾选Screen1的Scrollable属性(滚屏功能); 2\. 设置ConnectListPicker和DisconnectButton的宽度为“Fill parent”; 3\. 设置VerticalArrangement1、ForwardButton、HorizontalArrangement1、LeftButton、StopButton、RightButton及BackwardButton的Width与Height为“Fill parent”; 4\. 设置ConnectListPicker的Text属性为“连接”; 5\. 设置ForwardButton的Text属性为“∧”; 6\. 设置LeftButton的Text属性为“<”; 7\. 设置StopButton的Text属性为“—”; 8\. 设置RightButton的Text属性为“>”; 9\. 设置BackwardButton的Text属性为“∨”; 10\. 设置DisconnectButton的Text属性为“断开连接”; 11\. 设置ConnectListPicker和DisconnectButton的FontSize属性为30; 12\. 设置ForwardButton、LeftButton、StopButton、RightButton及BackwardButton的FontSize属性为40。 在这类应用中,当手机与NXT建立蓝牙连接之前,应该隐藏用户的操作界面,为此取消勾选VerticalArrangement1的Visible属性。不要担心,当NXT连通后,将重新显示用户界面。 ## **为组件添加行为** 本节将编程来设置应用的行为,包括: * 用户从列表中选择机器人,并与之建立连接; * 断开机器人与应用的连接; * 使用控制按钮来操控机器人; * 在机器人侦测到障碍物时,让它停下来。 ### **连接到NXT机器人** 添加第一个行为:连接到NXT。点击 ConnectListPicker将显示已配对的机器人列表,选中一个,将在应用与机器人之间建立蓝牙连接。 ### **显示机器人列表** 使用ConnectListPicker组件来显示机器人列表。ListPicker的外表像按钮,被点击后则显示列表项,并允许进行单选。 使用BluetoothClient1.AddressesAndNames块来提供列表,列表项是已经与Android设备配对的蓝牙设备的名称及地址。由于NXT已经将轮驱动及超声波组件的BluetoothClient属性设定为BluetoothClient1,因此AddressesAndNames属性列表中的设备会自动限定为这类机器人,其他类型的蓝牙设备(如耳机)将不会出现在列表中。表12-3列出了所需要的块。 **表12-3 在应用中添加ListPicker列表所需要的块** |块的类型 | 所在抽屉 | 作用 | | --- | --- | --- | | ConnectListPicker.BeforePicking | ConnectListPicker |当ConnectListPicker被点击时,触发该事件 | | set ConnectListPicker.Elements to | ConnectListPicker |为ConnectListPicker设置可供选择的列表项 | #### **块的作用** 点击ConnectListPicker将触发ConnectListPicker.BeforePicking事件,并显示可选项列表。将ConnectListPicker.Elements属性设置为 BluetoothClient1.AddressesAndNames块,来设定可选项;ConnectListPicker将显示已经与Android设备配对的机器人列表。 ![{%}](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd4f13d9d.png) **图 12-3 显示机器人列表** > ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd4f79e4c.png) 测试:在手机上点击“连接”,看看会发生什么,你会看到所有已经与手机配对的机器人列表。 如果只见黑屏,说明手机尚未与任何机器人配对;如果见到其他蓝牙设备,如蓝牙耳机,说明 NxtDrive1与 NxtUltrasonicSensor1的BluetoothClient属性设置有误。 ### **建立蓝牙连接** 从列表中选择一个机器人,应用将通过蓝牙与机器人连接。如果连接成功,用户界面将发生变化:隐藏ConnectListPicker,并显示用户界面的其余部分。如果机器人开关没有打开,则连接失败,会弹出错误信息。 使用call BluetoothClient1.Connect块与机器人进行连接。ConnectListPicker.Selection属性提供了选中机器人的地址和名称信息。 使用ifelse块来测试连接是否成功。ifelse块需要连接三个不同的块:“if”、“then”及“else”。“if”与BluetoothClient1.Connect块连接,“then”区域放置连接成功时要执行的块;“else”区域放置连接失败时要执行的块。 如果连接成功,使用Visible属性来隐藏 ConnectListPicker并显示VerticalArrangement1(其中放置了除ConnectListPicker之外的所有组件)。如果连接失败,则使用Notifier1.ShowAlert块来显示错误信息。表12-4列出了设置上述行为所需的块。 **表12-4与机器人建立蓝牙连接所需的块** | 块的类型 | 所在抽屉 | 作用 | | --- | --- | --- | | ConnectListPicker.AfterPicking | ConnectListPicker |当从ConnectListPicker选中一个机器人时触发| | ifelse | Control | 检验蓝牙连接是否成功 | | call BluetoothClient1.Connect | BluetoothClient1 |连接到机器人 | | ConnectListPicker.Selection | ConnectListPicker |选中的机器人的地址及名称 | | set ConnectListPicker.Visible to | ConnectListPicker|隐藏ConnectListPicker按钮 | | false | Logic | 插入set ConnectListPicker.Visible to块 | | set VerticalArrangement1.Visible to | VerticalArrangement | 显示“连接”按钮之外的所有组件 | | true | Logic | 插入set VerticalArrangement1.Visible to块 | | Notifier1.ShowAlert | Notifier1 | 用来弹出错误信息 | | “无法建立蓝牙连接。” | Text | 错误信息。 | #### **块的作用** 选中机器人后将触发ConnectListPicker.AfterPicking事件,见图12-4,BluetoothClient1.Connect块用于建立与机器人之间的蓝牙连接。如果连接成功,执行“then”块:隐藏ConnectListPicker按钮并显示VerticalArrangement1内的所有组件,即,设置ConnectListPicker.Visible属性为false,设置VerticalArrangement1.Visible属性为true。如果连接失败,执行“else”块:用Notifier1.ShowAlert块弹出错误信息。 ![{%}](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd54c9699.png) **图 12-4 建立蓝牙连接** ### **与NXT断开连接** 让Android设备与NXT机器人连接着实让人兴奋,不过“断开连接”是我们下面要添加的行为,这样便于对连接与断开进行连续测试。 当点击DisconnectButton时,应用将关闭蓝牙连接,用户界面将发生变化:ConnectListPicker按钮将重新出现,而用户界面上的其余组件将被隐藏。 表12-5列出了构建BluetoothClient1.Disconnect(断开蓝牙连接)所需的块。设置Visible属性来显示 ConnectListPicker按钮并隐藏VerticalArrangement1中包含的所有组件。 **表12-5 与机器人断开连接所需的块** | 块的类型 | 所在抽屉 | 作用 | | --- | --- | --- | | DisconnectButton.Click | DisconnectButton |当点击DisconnectButton时触发该事件 | | BluetoothClient1.Disconnect | BluetoothClient1 |断开与机器人的蓝牙连接 | | set ConnectListPicker.Visible to | ConnectListPicker|显示ConnectListPicker(“连接”按钮) | | true | Logic | 插入set ConnectListPicker.Visible to块 | | set VerticalArrangement1.Visible to | VerticalArrangement | 隐藏用户界面上的其余组件 | | false | Logic | 插入set VerticalArrangement1.Visible to | #### **块的作用** 点击DisconnectButton将触发DisconnectButton.Clicked事件,如图12-5所示,断开蓝牙连接要用BluetoothClient1.Disconnect块,之后设置ConnectListPicker.Visible属性为true来显示 ConnectListPicker,设置VerticalArrangement1.Visible属性为false来隐藏VerticalArrangement1。 ![{%}](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd552a414.png) **图 12-5 与机器人断开连接** > ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd4f79e4c.png) 测试:请确保机器人已经打开,点击手机上的“连接”按钮,并选择要连接的机器人。建立蓝牙连接需要一点时间。一旦连接成功,用户界面将显示机器人的控制按钮,以及“断开连接”按钮。 单击“断开连接”按钮:控制机器人的按钮会消失,“连接”按钮则重新出现。 ### **操控机器人** 下面是真正有趣的部分:添加前进、后退、左右转动及停止行为。不要忘记“停止”,否则你手中的机器人会失去控制! NxtDrive组件提供了五个块,用来驱动机器人的电机: * MoveForwardIndefinitely块:驱动两个电机前进; * MoveBackwardIndefinitely块:驱动两个电机后退; * TurnCounterClockwiseIndefinitely块:驱动机器人左转:让右侧电机向前而左侧电机后退; * TurnClockwiseIndefinitely块:驱动机器人右转:让左侧电机向前而右侧电机后退; * Stop将停止电机。 每个移动及转向块都有一个Power参数,需要与数字块配合使用,来设定机器人电机的输出功率,取值范围可以从 0到100。但如果设置的功率太小,电机会发出吱吱声而不运转。在本例中建议使用90(百分比)。表12-6中列出了所需的块。 **表12-6 用于控制机器人的块** | 块的类型 | 所在抽屉 | 作用 | | --- | --- | --- | | ForwardButton.Clic | ForwardButton|点击ForwardButton时触 | | NxtDrive1.MoveForwardIndefinitely | NxtDrive1 |驱动机器人前进 | | 数字90 | Math | 功率值 | | BackwardButton.Click | BackwardButton |点击BackwardButton时触发 | | NxtDrive1.MoveBackwardIndefinitely | NxtDrive1 |驱动机器人后退 | | 数字90 | Math | 功率值 | | LeftButton.Click | LeftButton | 点击LeftButton时触发 | | NxtDrive1.TurnCounterClockwiseIndefinitely | NxtDrive1 |驱动机器人逆时针转动 | | 数字90 | Math | 功率值 | | RightButton.Click | RightButton | 点击RightButton时触发 | | NxtDrive1.TurnClockwiseIndefinitely | NxtDrive1 |驱动机器人顺时针转动 | | 数字90 | Math | 功率值 | | StopButton.Click | StopButton | 点击StopButton时触发 | | NxtDrive1.Stop | NxtDrive1 | 让机器人停止 | #### **块的作用** 如图12-6所示,点击ForwardButton按钮时触发ForwardButton.Clicked事件,此时调用NxtDrive1.MoveForwardIndefinitely块,让机器人以90%的功率前进,其余按钮的事件处理程序与此类似,并以相同的功率驱动机器人后退及左右转动。点击StopButton时触发StopButton.Clicked事件,调用NxtDrive1.Stop块让机器人停止运动。 ![{%}](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd6ae8611.png) **图 12-6 操控机器人** > ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd4f79e4c.png) 测试:按照此前的“测试”说明,先连接NXT机器人。不要将机器人放在桌子上,以免跌落,然后测试以下行为: > > 1\. 点击前进按钮,机器人应该向前移动; > > 2\. 点击后退按钮,机器人应该向后移动; > > 3\. 点击左转按钮,机器人应逆时针转动; > > 4\. 点击右转按钮,机器人应顺时针转动; > > 5\. 点击停止按钮,机器人应停止。 > > 如果机器人不动并发出吱吱声,可能需要加大电机的功率,可以用最大功率100。 ### **用超声波传感器探测障碍物** 使用超声波传感器的机器人可以侦测到30厘米范围内的障碍物,遇到障碍物时机器人会像罪犯一样停下来,如图12-7所示。 ![{%}](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd75ab082.png) **图 12-7 为NXT机器人设置障碍** NxtUltrasonicSensor组件用于侦测障碍物,两个属性BottomOfRange和TopOfRange用来定义侦测范围(以厘米为单位)。默认设定BottomOfRange为30厘米,TopOfRange为90厘米。 NxtUltrasonicSensor组件具有三个事件BelowRange、WithinRange及boveRange,当侦测到障碍物在BottomOfRange(下限)距离以内时,会触发BelowRange事件;当障碍物的距离在BottomOfRange与TopOfRange (上下限)之间时,会触发WithinRange事件;当障碍物的距离超过TopOfRange(上限)时,将触发AboveRange事件。 这里使用NxtUltrasonicSensor1.BelowRange事件块,用来侦测30厘米以内的障碍物,如果你想尝试侦测不同距离的障碍物,可以调整BottomOfRange属性。当BelowRange时间发生时,使用NxtDrive1.Stop块让机器人停下来。表12-7中列出了所需的块 **表12-7 使用NxtUltrasonicSensor需要的块** | 块的类型 | 所在抽屉 | 作用 | | --- | --- | --- | | NxtUltrasonicSensor1.BelowRange | NxtUltrasonicSensor1 |超声波传感器在30厘米内遇到障碍物时触发 | | NxtDrive1.Stop | NxtDrive1 | 让机器人停下来 | #### **块的功能** 当机器人的超声波传感器侦测到30厘米以内的障碍物时,NxtUltrasonicSensor1.BelowRange事件被触发,如图12-8所示,此时NxtDrive1.Stop块让机器人停下来。 ![{%}](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd7bba9bd.png) **图 12-8 侦测障碍物** > ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-31_55e3fd4f79e4c.png) 测试:按照此前的“测试”说明,先连接NXT机器人。引导机器人朝着障碍物(如猫)的方向前进,机器人将在距离猫30厘米时停下来。如果机器人没停下来,可能是猫已经远离了机器人,它们之间的距离一直大于30厘米。可以换一个静止的障碍物来进行测试。 ## **改进** 应用运行起来,想必你已经花了大量时间来操控这个机器人,不过还是想继续其他的尝试: * 调节驱动电机的输出功率: * 可以修改插入到前进(MoveForwardIndefinitely)、后退(MoveBackwardIndefinitely)、左转(TurnCounterclockwiseIndefinitely)及右转(TurnClockwiseIndefinitely) 块中的数字块的值。 * 当侦测到障碍物时,使用NxtColorSensor让红灯闪烁: * 可以使用NxtColorSensor组件及其GenerateColor属性; * 需要将DetectColor属性设置为false(或在组件设计器取消勾选该属性),因为颜色传感器无法同时检测和产生颜色。 * 使用Android的方向传感器OrientationSensor来控制机器人。 * 使用乐高的构造元件建立手机与机器人之间的物理连接,创建应用实现机器人的自主性。 ## **小结** 以下是本章涵盖的内容: * ListPicker组件:让用户可以从已配对的机器人列表中进行选择; * BluetoothClient组件:使Android设备与机器人建立连接; * Notifier组件:用来显示错误消息; * Visible属性:用于隐藏或显示用户界面中的组件; * NxtDrive组件:可以控制机器人的移动、转向及停止; * NxtUltrasonicSensor组件:用于侦测障碍物。 ### **外部链接** [LEGO MINDSTORMS EV3控制程序](http://blog.sina.com.cn/s/blog_6210c9730101jqui.html) [Android应用控制LEGO EV3(Video)](http://blog.sina.com.cn/s/blog_62218b990101k4yr.html)
';