原文:Beginning Robotics Programming in Java with LEGO Mindstorms
一、乐高 MindStorm 和 leJOS 简介
Electronic supplementary material The online version of this chapter (doi:10.1007/978-1-4842-2005-4_1) contains supplementary material, which is available to authorized users.
本章提供了如何使用乐高 MindStorm EV3 公司建立 Java 机器人编程环境的分步指南,包括乐高 MindStorm EV3 公司的基本概述和莱霍斯·EV3 公司的介绍。本章包括如何在你的计算机上安装莱霍斯 EV3 开发系统,如何在乐高 EV3 积木上安装莱霍斯 EV3 固件,以及如何安装和应用 Eclipse IDE 的莱霍斯 EV3 插件。最后,您将创建第一个名为 HelloWorld 的 Java 机器人程序,通过 USB 电缆将 HelloWorld 程序从您的计算机上传到乐高 EV3 积木中,并在乐高 Mindstorms EV3 上执行该程序。
乐高 MindStorm 简介
乐高 MindStorm 是一款来自乐高的教育产品,旨在帮助您轻松构建机器人。该产品系列已经发展了几十年,乐高 MindStorm EV3 是第三代。图 1-1 展示了一个典型的乐高 MindStorm EV3 机器人套装,其中 EV3 砖块是乐高 MindStorm EV3 的大脑。这是一个智能的可编程设备,让乐高机器人执行各种智能操作。
图 1-1。
Lego Mindstorms EV3
如图 1-1 所示,乐高 Mindstorms EV3 的典型组件包括电机端口、传感器端口、PC 连接端口、扬声器和 EV3 按钮。关于乐高 MindStorm EV3 组成部分的更多细节可以在: http://www.lego.com/en-us/mindstorms/downloads
找到。
乐高 MindStorm EV3 中的电机端口有四个用于连接电机的输出端口:端口 A、B、C 和 d
传感器端口有四个用于连接传感器的输入端口:端口 1、2、3 和 4。
迷你 USB PC 连接端口用于将 USB 电缆连接到您的本地计算机,并将程序下载到 EV3 砖块(或将数据从机器人上传到您的本地计算机)。您还可以使用无线蓝牙连接上传和下载程序。
乐高 MindStorm EV3 中包含的扬声器使程序具有真实的声音成为可能,你可以在运行程序时听到它们。
您可以在 EV3 砖块的中心应用一个深灰色按钮来打开电源、输入命令或运行程序。砖块的左上角还有一个浅灰色的按钮,用于反转动作、中止程序和关闭 EV3。EV3 砖块上的其他四个浅灰色按钮用于在 EV3 菜单中向左、向右、向上和向下移动。
乐高 MindStorm EV3 的典型技术规格如下。关于乐高 EV3 规格的更多细节可以在 http://www.lego.com/en-us/mindstorms/downloads
找到。
- 单个主处理器控制机器人:
- 运行频率为 300 MHz 的 32 位 ARM9 处理器
- 能够访问 64 MB 内存
- 使用 16 MB 闪存
- 操作系统是基于 Linux 的
- 使用 6 节 AA 电池或稍大的可充电电池组运行:
- 虽然 6 节 AA 电池理论上相当于 9 伏,但你更可能体验到大约 7-8 伏,这取决于电池中的电荷
- 包含四个电机/伺服端口:
- 三个马达(两个大型马达和一个中型马达)配有每个乐高 MindStorm EV3 套件
- 包含四个传感器端口:
- 配有各种传感器:
- -触摸
- -颜色
- 超声波
- 陀螺仪
- 配有各种传感器:
- 交流:
- 自带蓝牙
- 一个程序可以加载到 EV3 砖使用蓝牙以较慢的速度或使用 USB 电缆以更快的速度
- 可以被编程以允许在程序执行时在两个(或多个)EV3 砖块之间进行通信
- 当程序正在执行时,第三方软件可用于 PC 和 EV3 砖之间的通信
- 包括一个内置的 178 × 128 像素 LCD 图形显示屏
leJOS 简介
“leJOS”的意思是 Lego for Java 操作系统,这是一种开源语言,用于使用 Java 技术为 Lego Mindstorms 产品开发软件。leJOS 项目支持乐高 MindStorm EV3,以及以前的版本,包括乐高 MindStorm NXT 和乐高 MindStorm RCX。leJOS 项目为 Lego Mindstorms 提供了以下解决方案:
乐高 Mindstorms EV3
- EV3 砖的 JVM
- EV3 砖的 leJOS API
- leJOS PC 通信
- 远工具
乐高 Mindstorms NXT
- 用于 NXT 块的 JVM
- 用于 NXT 砖的 leJOS API
- leJOS PC 通信
- leJOS JavaME 通信公司
- 远工具
乐高 Mindstorms RCX
- RCX 砖的 JVM
- RCX 砖的 leJOS API
- leJOS PC 通信
- 远工具
在这本书里,我们关注的是最新的乐高 MindStorm 产品:也就是乐高 MindStorm EV3。表 1-1 显示了 leJOS 为 EV3 砖提供的典型官方包装。这些软件包允许你管理 EV3 砖,传感器,执行器,以及其他一些 EV3 硬件。
表 1-1。
EV3 brick packages
| 包裹 | 描述 | | --- | --- | | 远点,硬件 | 支持 EV3 硬件 | | 远点,硬件,ev3 | 要访问 EV3 硬件 | | 远点,硬件,lcd | 要访问 EV3 液晶显示器 | | 很远,硬件,引擎 | 去 EV3 汽车公司 | | 远点,硬件,端口 | 进入 EV3 港口 | | 远点,硬件,传感器 | 要访问 EV3 上支持的所有传感器 | | 远点,硬件,视频 | 要访问视频设备 |表 1-2 列出了为一些机器人问题提供支持的包,比如定位和导航。
。
Robotics/AI packages
| 包裹 | 描述 | | --- | --- | | lejos .机器人.本地化 | 本地化支持 | | lejos .机器人学.制图 | 支持地图 | | lejos .机器人.导航 | 导航类 | | lejos.robotics .对象检测 | 对象检测类 | | 机器人学包容 | 支持包容架构 |所有 leJOS 版本都有 Javadoc 格式的包文档。有关 EV3 莱霍斯酒店提供的套餐详情,请访问: http://www.lejos.org/ev3/docs/
。
图 1-2 显示了莱霍斯 EV3 开发文件。
图 1-2。
leJOS development documents
JDK 装置
leJOS 项目基于 Java 技术,所以您需要在本地计算机上安装 Java 开发工具包(JDK)当前版本。JDK 发布可以在: http://www.oracle.com/technetwork/java/index.html
找到。
Java 运行时环境(JRE)是不够的,因为它不允许您编译 Java 程序。莱霍斯·EV3 只支持 32 位版本的 JDK 和 JRE,所以即使你有 64 位系统,你也应该选择 32 位版本的 JDK。此外,莱霍斯·EV3 已经在 1.7 版上进行了测试,因此本书推荐使用 Java 7。作为一个例子,下面的步骤向您展示了如何使用名为jdk-7u45-windows-i586.exe
的 Java JDK 安装程序来安装 JDK。
Installing The Jdk
-
Double-click the file
jdk-7u45-windows-i586.exe
, and you will see the screen shown in Figure 1-3. Then, click the Next button.图 1-3。
Step 1 of the JDK Installation
-
Install the JAVA JDK to the path
C:\Program Files (x86)\Java\jdk1.7.0_45
, choose all components, and click the Next button, as illustrated in Figure 1-4. It will then install JDK components that you chose.图 1-4。
Step 2 of the JDK installation
-
Click the Close button, as shown in Figure 1-5. The JAVA JDK is then successfully installed on your computer at:
C:\Program Files (x86)\Java\jdk1.7.0_45
.图 1-5。
Step 3 of the JDK installation
-
一旦你在电脑上安装了 J2SE 软件开发工具包,就有必要检查你是否能编译和执行任何 java 程序。
测试 JDK 安装
在您的计算机上打开一个 Shell 控制台,并键入命令Java
:
Java
:用于执行 Java 程序的 Java 命令Javac
:用于编译 Java 程序的 Java 命令
执行第一个测试的原因是因为您需要检查您的操作系统是否识别用于执行 Java 程序的命令java
。如果 shell 控制台返回使用该命令的选项,如图 1-6 所示,则测试成功。
图 1-6。
Test running the java command
第二个测试是必要的,以了解您的操作系统是否识别命令javac
,该命令用于编译您的程序。在键盘上键入javac
并检查消息。如果您的系统不能识别该命令,那么您必须更新计算机系统中的环境变量。右键单击“我的电脑”图标,然后选择属性。单击“高级选项”选项卡。当您单击此命令时,您将看到一个新窗口,您可以在其中更新变量路径。该路径用于直接从 Shell 键盘执行命令。
在选项卡高级选项选项卡上,点击环境变量按钮,如图 1-7 所示。path
变量位于系统变量区。找到变量path
,点击更新按钮。路径变量可能有许多语句,因为它们被许多应用使用。
图 1-7。
A screenshot of setting up environment variables
要更新path
变量,在你的计算机上找到 J2SE SDK 所在的路径。在这种情况下,路径是:
C:\Program Files (x86)\Java\jdk1.7.0_45\bin
知道路径后,将其添加到系统变量 path 内容的末尾。
您还需要创建一个名为JAVA_HOME
的新系统变量,并将其值设置为C:\Program Files (x86)\Java\jdk1.7.0_45
。一旦你做了更改,重新启动 DoS 命令窗口,并再次检查命令javac
。
如果您看到命令javac
的选项,如图 1-8 所示,那么测试是成功的——恭喜!您已经完成了 JDK 的安装。现在您可以使用您的计算机来开发 java 程序,并且您已经安装和配置了基本的 Java 工具。
图 1-8。
Test running the javac command
在乐高 EV3 上安装 leJOS 及其固件
leJOS 可以安装在主流的操作系统中,比如 Windows、Linux 和 Mac OS。既然你已经安装并运行了 Java,那么是时候在你的电脑上安装 leJOS 系统,并在乐高 Mindstorms EV3 上安装它的固件了。为此,您需要一张最大容量为 32GB 的空白 SD 卡。此外,SD 卡需要使用 FAT32 分区进行格式化。安装 leJOS 最简单的方法是在: http://www.lejos.org
下载安装程序。
Installing Lejos
-
访问
https://sourceforge.net/projects/ev3.lejos.p/files/0.9.1-beta/
,然后选择Download leJOS_EV3_0.9.1-beta_win32_setup.exe (41.8MB)
。然后你可以下载并保存leJOS_EV3_0.9.1-beta_win32_setup.exe
到你的电脑上。 -
Double-click
leJOS_EV3_0.9.1-beta_win32_setup.exe
, and you will see a leJOS EV3 Setup Wizard, as shown in Figure 1-9.图 1-9。
leJOS setup wizard
-
Click the Next button, and you will see the screen shown in Figure 1-10.
图 1-10。
Choosing the right JDK for use with leJOS EV3
-
Choose the 32-bit JDK that you installed, for example,
jdk1.7.0_45
, and then click the Next button. You will see the screen shown in Figure 1-11.图 1-11。
Choosing a folder to install leJOS EV3 program
-
Make sure that you have installed the JDK and set the path and
JAVA_HOME
to the installation directory of your JDK. You can click browse to select the path to which you want to install. In this example, I chose the destination folderC:\Program Files (x86)\leJOS EV3
. After you set up the installation folder, click Next button and you will see the screen shown in Figure 1-12.图 1-12。
Choosing ALL components of leJOS
-
Check to choose all of the components you wish to install, and then click Next button. You will see the screen shown in Figure 1-13.
图 1-13。
Selecting folders where to install the sample leJOS projects
-
Choose to install the Sample Projects and the Development Kit into root folder C, click Next, and then you can use the default setting to create a Start Menu folder called
leJOS EV3
. After that, click Next and you will see the screen shown in Figure 1-14.图 1-14。
General settings for the leJOS installation
-
Double-check to see if all of the settings are OK, and then click Install. You will see the installation progress bar, and eventually you will see the screen shown in Figure 1-15.
图 1-15。
Finishing the leJOS installation
-
Make sure that you have your SD card ready, and then click Finish. After that, a EV3SDCard utility program will start, as shown in Figure 1-16.
图 1-16。
EV3 SD Card creator
-
Choose the right SD Card drive, click the link to Download the EV3 Oracle JRE, and select the corresponding
.gz
file. Then click the Create button and you will see that the EV3 firmware is burned into the SD card, as shown in Figure 1-17.

图 1-17。
Installing the leJOS firmware into the SD card
创建 SD 卡后,将它插入 EV3 砖,按下中间的深灰色按钮启动 EV3,并在 EV3 砖上完成 leJOS 固件安装。leJOS EV3 的标志将显示在砖块的 LCD 上。安装完成后,将显示一个 leJOS EV3 菜单,默认 IP 地址显示在顶部(10.0.1.1
)。至此,您已经准备好进行下一步,将用于开发 leJOS 程序的 Eclipse 插件安装到 EV3 砖中。
莱霍斯·EV3 的 Eclipse IDE 和 Eclipse 插件
当然,仅仅使用文本编辑器和命令行也可以进行 Java 编程。然而,对程序员来说,点击按钮让事情发生要比输入命令和可选参数容易得多。一般来说,标准的文本编辑器并不包含很多在编辑代码时可以帮助你的特性,而且当你拼错了一个类名或者遗漏了一个括号时,它们也不会告诉你。集成开发环境(IDE)是一种工具,允许您使用简单的按钮输入、编译和上传代码到 EV3,它还通过对代码进行颜色编码来监控代码语法,以便您可以轻松识别关键字和变量。最好的开源 ide 之一是 IBM 的 Eclipse,它是免费的,功能强大,易于使用。这一节将向您展示如何在 leJOS EV3 上为 Java 编程设置 Eclipse IDE。
第一步,在: http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/indigosr1
下载 Eclipse,搜索面向 Java 开发者的 Eclipse IDE。请注意,即使您使用的是 64 位计算机,也需要下载 32 位版本的 Eclipse IDE,因为莱霍斯·EV3 插件不能与 64 位版本的 Eclipse 一起工作。下载的是一个.zip
文件,您必须将文件解压缩到一个目录中。这将是 Eclipse 程序的永久位置。要运行 Eclipse,只需双击 Eclipse 目录中的可执行文件。类似地,为了删除 Eclipse,您只需从您的计算机上删除 Eclipse 目录。
第一次运行 Eclipse 时,它会询问您工作区的位置。在本实验中,您可以选择工作区作为用于安装 leJOS 的文件夹,在本例中为C:\leJOSEV3Proj
,如图 1-18 所示。
图 1-18。
Setting up the workspace for Eclipse
如果有软件补丁或新功能,您可以通过点击Window -> Preferences
,双击列表中的Install/Update
,突出显示自动更新,将 Eclipse 设置为自动搜索更新。如图 1-19 所示,勾选自动查找新更新并通知我,然后点击确定。之后,Eclipse 及其插件将自动更新。
图 1-19。
Setting up automatic updates in Eclipse Installing The Eclipse Ide And Eclipse Plu-Gin
既然已经安装了 Eclipse,那么是时候安装莱乔斯 have 插件了。请遵循以下步骤:
-
In Eclipse, select
Help > Install New Software
. You will see a dialog requesting that you input a URL, as shown in Figure 1-20.图 1-20。
Step 1 of installing the leJOS EV3 plug-in
-
Click Add, and you will see another dialog box, as shown in Figure 1-21. Enter the name leJOS EV3, and for the location enter this:
http://lejos.sourceforge.net/tools/eclipse/plugin/ev3
.图 1-21。
Step 2 of installing the leJOS EV3 plug-in
-
Click OK. You should see a new item in the main dialog box, as shown in Figure 1-22. Place a check mark in the box next to the new item, and click the Next button.
图 1-22。
Step 3 of installing the leJOS EV3 plug-in
-
阅读并接受许可协议,然后单击“下一步”按钮。插件将自动安装。
-
完成后,会要求您重启 Eclipse。一旦它重新启动,您将在 Eclipse 中看到一些微妙的变化。该插件将在 Eclipse 中的许多地方添加新的 leJOS 菜单项。
-
Eclipse will automatically look for the
EV3_HOME
environment variable to locate leJOS EV3. Check to make sure that the preferences are what you like. SelectWindows -> Preferences
and then leJOS EV3 from the list. If the leJOS EV3 directory is not correct, either type in the location or browse to it. Make sure that you browse to the main directory and not one of its subdirectories. After that, you need to double-check if they are the same as the items illustrated in Figure 1-23.图 1-23。
Preferences for the leJOS EV3 plug-in
Creating And Uploading A Program: Helloworld
现在您需要创建一个输入代码的地方。Eclipse 将单个 Java 项目保存在自己的项目目录中。例如,如果您创建一个处理映射的大型多类项目,您将在它自己的目录中创建您自己的项目来存储类和数据文件。
在本节中,您将创建一个用于存储代码的项目。
-
选择
File > New > Project
。 -
In the next window, double-click leJOS EV3 to expand the folder options. You want to create a leJOS EV3 project, so select leJOS EV3 project and click the Next button, as shown in Figure 1-24.
图 1-24。
A New leJOS project
-
For the project name , enter
test
and then click Finish, as shown in Figure 1-25.图 1-25。
Create a new leJOS EV3 project
-
In order to add a new class file, select
File > New > Class
. EnterHelloWorld
in the name field, as shown in Figure 1-26. Eclipse will also offer other options, such as automatically adding amain()
method. Check this if you want Eclipse to do some of the typing for you.图 1-26。
Add a class in the new leJOS EV3 project
-
完成后点击
Finish
按钮。您应该会看到一个包含一些起始代码的新类文件。在文件中输入随后的HelloWorld
代码。//************************************************************ //Wei Lu Java Robotics Programming with Lego EV3 Hello World.java //An example to display HelloWorld on the LCD screen of EV3 brick //************************************************************ // import EV3 hardware packages for EV brick finding, // activating keys and LCD import lejos.hardware.ev3.EV3; import lejos.hardware.BrickFinder; import lejos.hardware.Keys; import lejos.hardware.lcd.TextLCD; public class HelloWorld { public static void main(String[] args) { // get EV3 brick EV3 ev3brick = (EV3) BrickFinder.getLocal(); // instantized LCD class for displaying and Keys // class for buttons Keys buttons = ev3brick.getKeys(); TextLCD lcddisplay = ev3brick.getTextLCD(); // drawing text on the LCD screen based on // coordinates lcddisplay.drawString("HelloWorld", 2, 4); // exit program after any button pressed buttons.waitForAnyPress(); } }
-
Click the Save button, turn on your EV3 brick, and then click the green Run button in the Eclipse toolbar. A pop-up window will appear the first time that you click the Run button for a class file. Select the leJOS EV3 program, as shown in Figure 1-27, and click OK. The program will begin uploading. You need to make sure that the EV3 brick is connected to your computer through the mini-USB port .
图 1-27。
Running a leJOS EV3 program
当程序上传并自动运行时,您的 EV3 将在屏幕中央显示HelloWorld
,假设您使用的是默认设置。如果您不想让程序在每次上传时自动运行,请选择Windows > Preferences > leJOS EV3
并取消选中上传后运行程序。
摘要
本章让你开始在你的本地计算机上安装 JDK 和莱霍斯系统,并使用外部 SD 卡在乐高 MindStorm EV3 积木上刻录莱霍斯 EV3 固件。您还使用 leJOS 和您的机器人运行了第一个名为HelloWorld
的 Java 机器人程序。leJOS 可以安装在主流的操作系统中,比如 Windows、Linux 和 Mac OS。特别是,您在本章中学到了以下内容:
- 如何安装莱乔斯 EV3 软件到您的 Windows 操作系统与莱乔斯安装程序。
- 如何安装莱霍斯 EV3 固件到你的乐高 EV3 砖。
- 如何为 Eclipse IDE 安装和使用 leJOS 插件。
- 如何在 Eclipse 中编写源代码,然后上传并在您的 EV3 砖上运行程序。
- 如何在本地计算机上安装和配置 JDK。
在下一章中,您将了解 EV3 大型电机及其在莱霍斯 EV3 提供的相应电机类别。然后,在此基础上,你将学习如何使用电机控制基本运动,如何中断旋转,如何调节电机速度,以及如何跟踪直线。
二、电机传感器简介
本章介绍了 EV3 大型伺服电机及其在 EV3 莱霍斯提供的相应电机类别。特别是,本章包括六个示例 Java 项目,涵盖以下主题:
- 使用电机控制基本运动
- 使用转速表进行惯性测试
- 控制电机的精确旋转
- 中断旋转
- 调节电机速度
- 描绘一条直线
Java 编程的基本概念
莱霍斯 EV3 基础设施使用 Java 编程语言为乐高 MindStorm EV3 机器人开发和实现软件系统。Java 是一种面向对象的编程语言,已经广泛应用于软件工程行业。这本书的目的不是指导你学习 Java 编程语言。相反,它假设您已经有了一些基本的 Java 编程经验。
任何 Java 程序都有一个用来管理所有操作的主要部分。在 Java 中,所有文件都是类,但是只有一个 Java 类具有方法main
。在你在第一章中开发的示例程序HelloWorld.java
中,公共方法main
在下面的程序中说明:
// import EV3 hardware packages for EV brick finding,
// activating keys and LCD
import lejos.hardware.ev3.EV3;
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.lcd.TextLCD;
public class HelloWorld {
public static void main(String[] args) {
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displaying and Keys // class for buttons
Keys buttons = ev3brick.getKeys();
TextLCD lcddisplay = ev3brick.getTextLCD();
// drawing text on the LCD screen based on
// coordinates
lcddisplay.drawString("Hello World", 2, 4);
// exit program after any button pressed
buttons.waitForAnyPress();
}
}
在上面的HelloWorld.java
程序清单中,lcddisplay.drawString
用于在乐高 EV3 LCD 显示屏上打印文本Hello World
,类似于在 DoS 命令窗口上打印Hello World
的语句System.out.println("Hello World")
。
在这个例子中,HelloWorld.
java
是一个简单的项目,有一个唯一的类。然而,在实践中,一个 Java 项目通常是复杂的,所以通常你会有多个类,其中一个将操纵其余的类。总之,任何 Java 类都包括一个导入区域、类封装和main
方法。导入区域声明您将在一个特定的类中使用什么 Java 包。例如,在HelloWorld.java
程序中,您使用 EV3 键和 LCD 功能,然后需要您导入包lejos.hardware.Keys
和lejos.hardware.lcd.*
。在main
方法中,main
类需要一个main
方法来执行它。在HelloWorld
类的例子中,它有一个main
类用来执行一些指令;即lcddisplay.drawString("Hello World", 2, 4)
在 LCD 屏幕上打印第 2 行第 4 列的Hello World
,按下 EV3 砖上的任意按钮后buttons.waitForAnyPress()
退出程序。
电机简介
马达是乐高 EV3 套件中所有运动的来源,它们在本书的所有机器人项目中扮演着重要的角色。因此,本章将使您熟悉莱霍斯 EV3 公司提供的电机类别的操作。
使用在莱霍斯 EV3 中实现的运动算法,你可以设置 EV3 机器人精确地旋转到指定的度数,比如 240 度,而不越过这个目标度数。此外,您可以为轮式车辆设置恒定的速度,这可以通过实时调整功率水平来实现,这样当机器人向上或向下移动时,它可以保持与您建立的速度相同的速度。此外,电机类别使电机能够通过最初以低速启动并不断加速达到指定速度来加速到全速。因此,您可以命令电动机在一个方向上前进数千圈,然后让它们随时返回原点。这些功能为 EV3 机器人的创造性导航和手臂旋转打开了无限的思路。
要使用乐高 EV3 机器人套装中提供的三个马达,你必须导入lejos.hardware.motor
包。该软件包带有四个字段:A、B、C 和 D,用于四个电机端口,以及许多方法。关于这样做的细节,你可以在 http://www.lejos.org/ev3/docs/
查看 EV3 的 Java API 函数。例如,您可以使用以下语句设置连接到端口 A 的电机的速度:
EV3LargeRegulatedMotor LEFT_MOTOR =
new EV3LargeRegulatedMotor(MotorPort.A);
LEFT_MOTOR.setSpeed(720);
这段代码将设置LEFT_MOTOR
的速度,使其每秒滚动 720 度(即每秒旋转两次)。如果你想让这个马达继续前进,你可以这样说:
LEFT_MOTOR.forward();
接下来,提供六个示例 Java 项目来介绍用于控制马达的马达类。您需要编译、上传并运行所有六个示例程序来完成本章中的所有任务。
介绍电机类
电机类提供对 EV3 大型伺服电机的访问。当控制 EV3 的运动时,电机必须连接到四个 EV3 电机端口中的一个。该类为每个端口提供了一个实例,即 MotorPort。答:汽车港。b,汽车港。c 和 MotorPort.D。
这四个对象中的每一个都是类EV3LargeRegulatedMotor
的一个实例,它提供了控制电机的方法。在本节中,给你一套六个程序,通过使用它们,你可以进行实验,以了解 EV3 大型电机如何运行。这些程序足够简单,所以编写它们不需要太多 Java 编程经验。尽管如此,它们仍然可以让你对编程和控制电机运动有一个基本的了解。
使用电机控制基本运动
这个程序使用控制运动的基本运动方法。本程序中使用的方法包括表 2-1 中所示的方法:
表 2-1。
Basic Motor Methods
| 班级 | 方法 | 功能 | | --- | --- | --- | | ev3 大型调节电机 | `forward()` | 电机正转。 | | | `backward()` | 电机反向旋转。 | | | `stop()` | 电机快速停止。 | | 键 | `waitForAnyPress` | 等到任何键被按下。 | | 液晶显示 | `drawString(String str,` `int x, int y)` | 在 lcd 的捐赠行 x 和 y 列打印一个文本字符串。 |该程序应该执行以下操作:
- 正向运行电机 A 和 C。
- 在顶行向前显示。
- 等到按钮被按下。
- 反向运行电机 A 和 C。
- 在下一行向后显示。
- 等到按钮被按下。
- 停止电机 A 和 c。
以下程序实现了上面定义的电机运动:
//***************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 p1.java
//Simple motor testing
//***************************************************************
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.ev3.EV3;
import lejos.hardware.lcd.LCD;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
public class p1 {
public static void main(String[] args) {
EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
EV3LargeRegulatedMotor RIGHT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.C);
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displaying
// and Keys class for buttons
Keys buttons = ev3brick.getKeys();
// block the thread until a button is pressed
buttons.waitForAnyPress();
// move robot forward and display status on LCD
// change directions when button is pressed
LEFT_MOTOR.forward();
RIGHT_MOTOR.forward();
LCD.drawString("FORWARD", 0, 0);
// block the thread until a button is pressed
buttons.waitForAnyPress();
// move robot backward and display status on LCD
LEFT_MOTOR.backward();
RIGHT_MOTOR.backward();
LCD.drawString("BACKWARD", 0, 1);
// block the thread until a button is pressed
buttons.waitForAnyPress();
// stop robot and display status on LCD
LEFT_MOTOR.stop();
RIGHT_MOTOR.stop();
LCD.drawString("STOP", 0, 2);
// exit program after any button pressed
buttons.waitForAnyPress();
}
}
使用转速表进行惯性测试
EV3 大型伺服电机有一个内置的转速表,跟踪电机轴的当前角度(以度为单位)。该程序的目的是使用转速表找出电机停止的速度。
该程序应该执行以下操作:
- 将电机速度设置为 720。
- 运行 MotorPort。一个前锋。
- 等到转速表计数达到 720。
- 停止马达。
- 在 LCD 上显示转速表读数。
- 等到电机实际停止。
- 在 LCD 上再次显示转速表读数。
- 等待按钮按下,给你时间来记录屏幕显示。
由于马达的惯性,你会发现在你调用方法stop()
后,马达并没有立即停止。本程序中使用的新方法包括表 2-2 中所示的方法:
表 2-2。
Methods Used in Tachometer
| 班级 | 方法 | 功能 | | --- | --- | --- | | ev3 大型调节电机 | `getTachoCount ()` | 获取以度为单位的电机角度。 | | | `resetTachoCount ()` | 将计数器数字重置为 0。 | | | `setSpeed(int speed)` | 以每秒度数设置旋转速度。 | | | `getRotationSpeed()` | 获取电机的实际速度,单位为每秒度数。 | | | `clear()` | 清除 LCD 屏幕。 |//************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 p2.java
//Motor inertia test
//************************************************************
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.ev3.EV3;
import lejos.hardware.lcd.LCD;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
public class p2 {
public static void main(String[] args) {
EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displaying and Keys // class for buttons
Keys buttons = ev3brick.getKeys();
// block the thread until a button is pressed
buttons.waitForAnyPress();
// set motor to move 720 degrees per second
LEFT_MOTOR.setSpeed(720);
// start forward movement
LEFT_MOTOR.forward();
// a counter to count the number of degrees
// rotated
int count = 0;
// continue moving until motor has rotated 720
// degrees
while (count < 720)
count = LEFT_MOTOR.getTachoCount();
// stop the motor
LEFT_MOTOR.stop();
// display the tachometer reading
LCD.drawString("Tacho Read: " + count, 0, 0);
// wait for motor to actually stop and display
// tacho count.
// this number will be higher than previous due // to motor inertia
while (LEFT_MOTOR.getRotationSpeed() > 0);
LCD.drawString("Tacho Read: " + LEFT_MOTOR.getTachoCount(), 0, 1);
// block the thread until a button is pressed
buttons.waitForAnyPress();
LCD.clear();
}
}
运行上述程序后,你会发现液晶屏上印着两个数字。这两个数字是不同的。第一个数字显示调用stop()
方法时转速计的读数。您可能希望这个数字是 720,因为程序在调用方法stop()
之前会等待转速计达到 720。然而,第二个数字高于第一个。这是因为当调用stop()
方法时,由于电机的惯性,电机不会立即停止。
控制电机的精确旋转
Motor 类提供了一个一直运行的调节器线程,您可以使用它在指定的角度停止电机。在这个例子中,您将运行一个测试来评估rotate()
方法的准确性。本程序中使用的方法包括表 2-3 中所示的方法:
表 2-3。
Methods Used in the Motor Class Regulator Thread
| 班级 | 方法 | 功能 | | --- | --- | --- | | ev3 大型调节电机 | `rotate(angle)` | 旋转定义角度的度数。 | | | `rotateTo(angle)` | 旋转到指定的角度。 |该程序应该执行以下操作:
- 将速度设置为 720。
- 将电机旋转一整圈。
- 在 LCD 第 0 行显示转速表读数。
- 将电机旋转至 360°角。
- 在 LCD 第 1 行显示转速表读数。
- 等待按钮按下,给你时间阅读液晶显示器。
- 清空液晶显示器。
根据电机调节器,电机通常在距指定角度不到 1 度时停止。这是通过计算制动后电机将继续运行多远来实现的。在达到指定角度之前应用制动,然后进行微调以微调电机位置,直到它足够接近。
//***************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 p3.java
//This program demonstrated motor rotation control
//***************************************************************
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.ev3.EV3;
import lejos.hardware.lcd.LCD;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
public class p3 {
public static void main(String[] args) {
EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displaying and Keys class // for buttons
Keys buttons = ev3brick.getKeys();
// block the thread until a button is pressed
buttons.waitForAnyPress();
// set motor to move 720 degrees per second
LEFT_MOTOR.setSpeed(720);
// rotate the motor one full revolution
LEFT_MOTOR.rotate(360);
// display the tacho count in row 0
LCD.drawString("Tacho Read: " + LEFT_MOTOR.getTachoCount(), 0, 0);
// rotate to the angle 360
LEFT_MOTOR.rotateTo(360);
// display the tacho count in row 1
LCD.drawString("Tacho Read: " + LEFT_MOTOR.getTachoCount(), 0, 1);
// block the thread until a button is pressed
buttons.waitForAnyPress();
LCD.clear();
}
}
通过在乐高 EV3 上运行上述程序,第一个转速表读数可能是 360,第二个是 359(或 360,取决于电机)。这两个数字相差不大。程序的第一步是旋转一整圈。那么它应该将电机设置到 360°位置。由于一次旋转是 360 度,因此预计这些数字会很接近。通过程序的演示,您可以观察到移动到某个位置比调用stop()
方法可以获得更好的精度。马达类预测马达应该停止的时间,并且更早地应用制动以弥补惯性的影响。
中断旋转
有时你会希望电机在达到某一特定角度之前停止或做些别的事情。在此示例程序中,如果您足够快地按下一个按钮,您将让代码检测到中断循环作业的按钮按下。在电机停止在目标角度之前,rotate()
方法不会返回。但是,您在这个程序中使用的新方法可以立即返回。本程序中使用的一些新方法包括表 2-4 中所示的方法:
表 2-4。
Rotate Method Used in the Motor Class
| 班级 | 方法 | 功能 | | --- | --- | --- | | ev3 大型调节电机 | `rotate(angle, immediateReturn)` | 旋转定义角度的度数,同时如果`immediateReturn`的值为真,该方法立即返回。 | | | `rotateTo(angle, immediateReturn)` | 旋转到指定的角度,同时如果`immediateReturn`的值为真,该方法立即返回。 | | | `(boolean) isMoving()` | 如果电机一直在旋转,则返回 true。 | | | `int readButtons()` | 如果按下任何按钮,返回按钮 id 号。 |该程序应该执行以下操作:
- 开始旋转 7200 度。
- 当电机旋转时,显示第 0 行位置的转速表计数。
- 按下按钮时,停止电机。
- 电机停止后,显示第 0 行位置的转速表计数。
- 记录从转速表读取的两个数字,然后等待按钮退出程序。
当您在旋转完成前按下按钮时,电机将停止旋转。
//************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 p4.java
//interrupting motors using buttons
//************************************************************
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.Sound;
import lejos.hardware.ev3.EV3;
import lejos.hardware.lcd.LCD;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
public class p4 {
public static void main(String[] args) {
EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displaying and Keys // class for buttons
Keys buttons = ev3brick.getKeys();
// sound two beeps before starting program
Sound.twoBeeps();
// block the thread until a button is pressed
buttons.waitForAnyPress();
// rotate 7200 degree during which the method has // returned value all the time
LEFT_MOTOR.rotate(7200, true);
// return to true if the motor is always rotating
while (LEFT_MOTOR.isMoving()) {
// display and refresh the tachometer reading all // the time
LCD.drawString("Tacho Read: " + LEFT_MOTOR.getTachoCount(), 0, 0);
// determining if there is any button
// pressed, if yes then stop the motor
if (buttons.readButtons() > 0)
LEFT_MOTOR.stop();
}
// wait until the motor fully stopped
while (LEFT_MOTOR.getRotationSpeed() > 0)
;
// display the tachometer reading after motor
// fully stopped
LCD.drawString("Tacho Read: " + LEFT_MOTOR.getTachoCount(), 0, 1);
// block the thread until a button is pressed
buttons.waitForAnyPress();
}
}
调节电机速度
电机类有一个调节器螺纹来控制电机速度。这样做的原因是,只有当两个马达以相同的速度运行时,两轮车才会直线行驶。leJOS EV3 保持每个电机旋转与系统时钟同步,因此调节器将转速表计数与速度乘以运行时间进行比较。然后,它调整功率,使这两个数字尽可能匹配。本程序中使用的一些新方法包括表 2-5 中所示的方法:
表 2-5。
Regulator Methods Used in the Motor Class
| | | 功能 | | --- | --- | --- | | 跑表 | `elapsed()` | 返回以毫秒为单位的运行时间。 | | | `reset()` | 将手表归零。 |秒表类包含在包lejos.util.Stopwatch
中。该程序应该执行以下操作:
- 创建一个新的秒表。
- 启动两台电机 A 和 C,以 1 转/秒的速度运行。(一转就是 360。)
- 每隔 200 毫秒,在同一行显示两个转速表计数值。
- 重复步骤 3 四次,每次使用不同的行。
- 打印出电机转速计计数之间的最大差值。
根据你的观察,这些电机应该保持在几度之内,因为我们使用了调节的大型电机 EV3 级。
//************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 p5.java
//Motor speed control comparison
//************************************************************
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.ev3.EV3;
import lejos.hardware.lcd.LCD;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
import lejos.utility.Stopwatch;
public class p5 {
static EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
static EV3LargeRegulatedMotor RIGHT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.C);
public static void main(String[] args) {
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displaying and Keys // class for buttons
Keys buttons = ev3brick.getKeys();
// block the thread until a button is pressed
buttons.waitForAnyPress();
// the row to print on
int tachoRow = 0;
// instantiated a stopwatch class for setting up // the timer
Stopwatch sw = new Stopwatch();
// set the motor speed to 1 revolution per second
LEFT_MOTOR.setSpeed(360);
RIGHT_MOTOR.setSpeed(360);
// motors moving forward
LEFT_MOTOR.forward();
RIGHT_MOTOR.forward();
// variables for determining the maximum
// difference in tacho counts
int maxTachoCountDiff = Integer.MIN_VALUE;
int currTachoCountDiff;
// perform four repetitions of the test
for (int i = 0; i < 4; i++) {
// wait for 200 milliseconds
sw.reset();
while (sw.elapsed() < 2000)
Thread.yield();
// display the tacho counts and reset the // max, if changed
currTachoCountDiff = displayTachoCounts(tachoRow++);
if (currTachoCountDiff > maxTachoCountDiff)
maxTachoCountDiff = currTachoCountDiff;
}
// stop the motors
LEFT_MOTOR.stop();
RIGHT_MOTOR.stop();
// display the maximum difference in tacho
// counts, then wait for exit
LCD.drawString("Max diff: " + maxTachoCountDiff, 0, tachoRow);
buttons.waitForAnyPress();
}
/**
* Displays the tachometer count for each motor
*
* @param row to print the count in
*
* @return Returns the difference between the tacho
* counts of the two motors
*/
private static int displayTachoCounts(int row) {
// store the tacho counts for the two motors
int tachoCountLeft = LEFT_MOTOR.getTachoCount();
int tachoCountRight = RIGHT_MOTOR.getTachoCount();
// display the tacho counts
LCD.drawString("M1: " + tachoCountLeft + " M2: " + tachoCountRight, 0, row);
// return the difference in the tacho counts
return Math.abs(tachoCountLeft - tachoCountRight);
}
}
通过运行上面的程序,您应该会观察到类似如下的结果:
Motor 1: 711 Motor 2: 710
Motor 1: 1493 Motor 2: 1492
Motor 1: 2212 Motor 2: 2212
Motor 1: 2934 Motor 2: 2934
Max diff: 1
两个转速表读数之间的最大差值为 1,因此您可以看出两个电机实际上是同步的。
描绘一条直线
在本练习中,您需要编写一个程序,让机器人向前运行一段预定的时间(比如 10,000 毫秒),并测量机器人行进的距离。该程序应该执行以下操作:
- 创建一个新的秒表。
- 启动两台电机 A 和 C 向前运行。
- 计算经过的时间,直到它达到 10,000 ms,在 LCD 屏幕上显示经过的时间。
- 停止两个电机。
- 计算距离与时间的比率,单位为厘米每秒。
重复你的程序三次,然后计算一个距离与时间的平均比,就是机器人的速度。
//******************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 p6.java
//Write a program to run the robot forward for some predetermined
//amount of time (say 10000 ms) and measure how far the robot went.
//******************************************************************
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.ev3.EV3;
import lejos.hardware.lcd.LCD;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
import lejos.utility.Stopwatch;
public class p6 {
static EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
static EV3LargeRegulatedMotor RIGHT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.C);
public static void main(String[] args) {
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displaying and Keys class // for buttons
Keys buttons = ev3brick.getKeys();
// block the thread until a button is pressed
buttons.waitForAnyPress();
// instantiated a stopwatch class for setting up the
// timer
Stopwatch watch = new Stopwatch();
// Begin running both motors
LEFT_MOTOR.forward();
RIGHT_MOTOR.forward();
// Clear the screen
LCD.clear();
// Reset the time on the watch
watch.reset();
// Display the elapsed time on the LCD until 10000ms
while (watch.elapsed() < 10000) {
Thread.yield();
LCD.drawString("" + watch.elapsed(), 0, 0);
}
// Stop the motors after 5 seconds
LEFT_MOTOR.stop();
RIGHT_MOTOR.stop();
buttons.waitForAnyPress();
}
}
平均而言,机器人在 10,000 毫秒内移动了 99.7 厘米,因此,机器人在以每秒 1 转的速度向前移动时,平均速度为 9.97 厘米/秒。考虑到胎面直径约为 3.1 厘米,电机速度设置为 360 度/秒,我们可以确认这一结果非常接近我们的预期;也就是 3.1 cm * 3.1415926 = 9.74 cm/s,和我们观测到的速度相当接近;即 9.97 厘米/秒。
其他运动方法
EV3 大型电机还提供了许多其他方法。表 2-6 中解释了其中一些方法:
表 2-6。
Other Methods
| 方法 | 功能 | | --- | --- | | `boolean isMoving()` | 这种方法有助于测试电机是否已完成旋转。`isMoving()`当电机因任何原因移动时,返回 true。例如,如果一个`forward()`或`backward()`方法被调用,或者一个`rotate()`任务正在进行中。 | | `int getLimitAngle()` | 返回电机当前旋转的角度,以度为单位。 | | `int getSpeed()` | 返回当前速度设置。 | | `int getRotationSpeed()` | 返回电机的当前速度,单位为每秒度数。 | | `boolean isStalled()` | 帮助您确定电机是否失速,或者电机速度调节是否失败。 | | `resetTachoCount()` | 该方法将转速表计数设置为 0,它重置调节器线程在决定何时停止旋转任务时使用的平均时间的原点。 | | `void setAcceleration(int acceleration)` | 这种方法有助于您控制电机速度从一种速度变化到另一种速度的速度。加速度以每秒的度数设置。 | | `void getAcceleration()` | 返回电机的当前加速度值,单位为每秒度数。 | | `suspendRegulation()` | 打开/关闭电机的调节。如果您想混合同一台电机的调节和非调节控制,可以使用这种方法。 |摘要
在这一章中,你学习了 EV3 电机的特点:电机如何旋转,如何设置电机的速度,以及速度调节的基本思想。具体来说,通过使用本章中提供的六个 Java leJOS 项目示例,您学习了如何编写和应用 leJOS Java 编程代码来控制和操作 Lego Mindstorms EV3 汽车。
在下一章中,你将会了解到在莱霍斯 next 的试点课程中提供的各种方法。您还将学习如何应用这些方法来控制轮式车辆,以便它可以描绘出具有预定长度的边的预定几何形状,包括正方形、三角形和六边形。
三、控制轮式车辆
本章介绍了 EV3 的 MovePilot 类中提供的各种方法。你将在飞行员课程中学习如何应用这些方法来控制轮式车辆,使其能够描绘出具有预定长度的边的预定几何形状,包括正方形、三角形和六边形。具体来说,本章包括九个示例 Java 项目,并涵盖以下主题:
- 导航 API 简介
- 使用飞行员课程的基本动作
- 使用
movepilot
和differentialpilot
描绘出一个正方形 - 使用
movepilot
和differentialpilot
描绘出一个三角形 - 使用
movepilot
和differentialpilot
描绘出一个六边形
导航 API 简介
你在第二章中学习了如何为 EV3 汽车创建一个简单的控制。例如,回顾以下电机测试程序,example1.java
:
//************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 example1.java
//an example for motor testing
//displaying tachocount about how many degrees rotated when //pressing //ESCAPE button.
//************************************************************
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.ev3.EV3;
import lejos.hardware.lcd.LCD;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
public class example1 {
static EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
public static void main(String[] args) throws Exception {
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displyang and Keys // class for buttons
Keys buttons = ev3brick.getKeys();
// block the thread until a button is pressed
buttons.waitForAnyPress();
String message = "MOTOR Testing: ";
// set up the motor A speed, i.e. 100 degrees per // second
LEFT_MOTOR.setSpeed(200);
// motor A moving forward
LEFT_MOTOR.forward();
// displaying number of degrees rotated on the
// LCD until an ESCAPE button is pressed!
while (buttons.getButtons() != Keys.ID_ESCAPE) {
LCD.clear();
LCD.drawString(message, 0, 1);
LCD.drawInt(LEFT_MOTOR.getTachoCount(), 0, 2);
Thread.sleep(1000);
LCD.refresh();
}
}
}
如example1.
java
所示,当开发一个 EV3 机器人程序来控制电机时,你需要指出你需要为任何动作编程哪个电机。在本例中,您使用以下指令设置电机 A 的速度:
static EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
LEFT_MOTOR.setSpeed(200);
After that you indicate that Motor A will turn forward using the following instruction:
LEFT_MOTOR.forward();
通常,如果您只是使用一个独特的电机,您可以使用的方法如下:
forward()
backward()
rotate()
rotateTo()
setSpeed()
stop()
在实际使用中,车辆通常配备两个车轮,由两个电机独立控制和导航。这种导航是通过 leJOS 导航 API 函数实现的,通过这些函数提供了一组类和方法来控制机器人。控制车辆的 leJOS NXJ 导航类处理分层抽象。
在底层,NXTRegulatedMotor
类被创建来控制转动轮子的马达。然后使用一个DifferentialPilot
类来控制电机的基本运动,例如原地旋转、直线行驶或弧形行驶。
在顶层,NavPathController
应用一个DifferentialPilot
来移动机器人通过平面上的复杂路径。一个OdometeryPoseProvider
也被用来记录机器人的位置和它前进的方向。在这样的层次结构中,控制流是基于自顶向下的方法;也就是说,路径控制器控制飞行员,然后飞行员控制马达。在这种情况下,信息流是自下而上的,飞行员从发动机收集信息来控制它们。姿态提供程序使用从飞行员处收集的里程表读数信息来更新其对机器人姿态的当前估计,包括机器人的笛卡尔坐标(即 x 轴和 y 轴)及其航向角(即基于度数的机器人面向的方向-面向正 x 轴方向为 0 度,面向正 y 轴方向为 90 度)。路径控制器使用所有这些信息来计算到目的地的距离和方向。在莱霍斯 EV3,一艘MovePilot
级被用来代替DifferentialPilot
。然而,基本思想是相同的。
使用飞行员课程的基本动作
这一章将介绍使用飞行员课程的基本动作,这是导航中最重要的步骤之一。正如你在第二章中看到的,仅仅使用马达类就可以移动机器人:也就是说,简单地通过向前和向后旋转马达。然而,为了驾驶到特定的位置(也就是说,进行精确的移动),有必要控制车辆向前或向后移动的距离以及机器人转动的角度。因此,使用 pilot 进行基本移动的主要目标是创建可以执行精确移动的车辆。pilot 类用于精确驾驶、驾驶和转向车辆,包括直线行驶、原地旋转、弧线和停止。
通过将这些运动的序列打包在一起,机器人可以通过重复执行两个基本步骤的组合从一个位置行进到另一个位置,例如机器人向前或向后行进的量以及机器人在整个运动中顺时针和逆时针旋转的量。
使用 pilot 类的一个好处是,除了飞行员,机器人的实际物理特征都隐藏在 navigator 包中。从内部运动的角度来看,机器人可以滚动、行走、跳跃或从一个位置飞到另一个位置。然而,从外部的角度来看,你只看到外部的飞行员方法,使机器人的动作看起来都一样。因此,使用 pilot 允许您对不同类型的机器人进行编程以参与导航,而不管它们的物理结构如何。
在 leJOS 中,一个Move
类被用来告诉机器人做什么动作,或者指示机器人刚刚做了什么样的动作。Move
类的一些核心方法包括:
getDistanceTraveled ()
获取车辆移动的距离,通常以厘米为单位。getTurnAngle ()
获取车辆在运动中旋转的角度,以度为单位。getArcRadius ()
接收车辆行驶的圆弧半径。
接下来,您将了解如何使用物理机器人来执行这些动作。在 leJOS 中,pilot 是一个控制特定机器人的类。特别是DifferentialPilot
级可以控制两个轮子的机器人。在这一章中,您将使用差动电机控制,因为它能够进行所有的移动,而且为它制造底盘也很简单。DifferentialPilot
级通过控制发动机的速度和旋转方向来驾驶车辆。飞行员对象需要知道马达连接到哪个端口,以及向前驱动马达是否使机器人向前或向后移动。该对象还需要知道车轮的直径和轨道的宽度:即两个车轮的轨道中心之间的距离。原因是DifferentialPilot
类使用车轮直径来计算它行驶的距离,使用轮距来计算它旋转了多远。所有这些信息都将传递给 pilot 构造函数,如以下代码行所示:
DifferentialPilot(float wheelDiameter, float trackWidth, Motor leftMotor, Motor rightMotor)
否则,使用以下构造函数将布尔变量 reverse 设置为 true,这样电机将向后旋转,使机器人向前移动:
DifferentialPilot(float wheelDiameter, float trackWidth, Motor leftMotor, Motor rightMotor, boolean reverse)
总之,为了控制机器人沿直线运动,可以使用以下方法:
void setTravelSpeed(double travelSpeed)
以相同的距离单位设置电机的速度(例如,如果车轮的直径以厘米为单位测量,则该方法设置的数值将以厘米/秒为单位)void forward()
启动机器人向前移动void backward()
启动机器人向后移动void stop()
停止机器人移动void rotate (double angle)
将机器人旋转一定角度
为了控制机器人移动的距离,可以使用以下方法:
void travel(double distance)
以与车轮直径相同的单位将电机移动指定的距离(即,如果车轮直径以厘米为单位,则该方法设置的数值将以厘米为单位)getMovement().getDistanceTraveled()
返回车辆行驶的距离
例如,下面的example2.java
展示了如何使用 leJOS NXJ 中的DifferentialPilot
类让机器人移动 20 厘米。
//****************************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 example2.java
//an example for making basic movement using DifferentialPilot //in leJOS NXJ
//****************************************************************************
import lejos.nxt.*;
import lejos.robotics.navigation.*;
public class example2 {
public static void main(String[] args) {
DifferentialPilot pilot = new DifferentialPilot(3.1, 17.5, Motor.A,Motor.C);
pilot.travel(20, true
); // 20 centimeters
pilot.rotate(90.0);
while (pilot.isMoving()) {
if (Button.ESCAPE.isPressed())
pilot.stop();
Button.waitForPress();
}
}
}
如example2.java
所示,您可以使用以下命令使机器人原地旋转指定的角度:
void rotate(double degrees)
此外,当使用这种方法产生精确的运动时,您需要精确地测量wheelDiameter
和trackWidth
的值。直径是从圆的一边到另一边的最宽的测量值。根据我的测量,我的机器人上的轮子直径是 3.1 厘米。为了在机器人转弯时记录精确的旋转,了解轮与轮之间的距离也很重要,即轮距。由于乐高轮胎是对称的,最好的方法是从一个轮胎的中心到另一个轮胎的中心进行测量。根据我的测量,上面例子中的轨道宽度是 17.5 厘米。DifferentialPilot
的最终参数是左右轮的电机。在上面的示例程序中,左马达连接到端口 A,右马达连接到端口 c。
由于MovePilot
在新的莱霍斯 EV3 中被用来代替DifferentialPilot
,下面的例子example3.java
提供给你一个在莱霍斯 EV3 使用MovePilot
的基本运动控制。
//************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 example3.java
//an example for making basic movement using MovePilot in //leJOS EV3
//************************************************************
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.ev3.EV3;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
import lejos.robotics.chassis.Chassis;
import lejos.robotics.chassis.Wheel;
import lejos.robotics.chassis.WheeledChassis;
import lejos.robotics.navigation.*;
public class example3 {
static EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
static EV3LargeRegulatedMotor RIGHT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.C);
public static void main(String[] args) throws Exception {
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displaying and Keys // class for buttons
Keys buttons = ev3brick.getKeys();
// block the thread until a button is pressed
buttons.waitForAnyPress();
// setup the wheel diameter of left (and right) motor // in centimeters, i.e. 2.8 cm
// the offset number is the distance between the center // of wheel to
// the center of robot, i.e. half of track width
Wheel wheel1 = WheeledChassis.modelWheel(LEFT_MOTOR, 2.8).offset(-9);
Wheel wheel2 = WheeledChassis.modelWheel(RIGHT_MOTOR, 2.8).offset(9);
// set up the chassis type, i.e. Differential pilot
Chassis chassis = new WheeledChassis(new Wheel[] { wheel1, wheel2 },WheeledChassis.TYPE_DIFFERENTIAL);
MovePilot pilot = new MovePilot(chassis);
// travel 100 centimeter
pilot.travel(100);
// rotate 90 degrees
pilot.rotate(90.0);
// press the ESCAPE button to stop moving
while (pilot.isMoving()) {
if (buttons.getButtons() == Keys.ID_ESCAPE)
pilot.stop();
}
// block the thread until a button is pressed
buttons.waitForAnyPress();
}
}
画出一个正方形
在本节中,您将开发一个程序来创建一个机器人,该机器人描绘出一个边长预定为 1 米的正方形。您将编写、编译并上传您的代码到 Lego Mindstorms。此外,你还需要计算出电机向前移动 N 厘米的距离需要多长时间;例如,在这种情况下,N 被设置为 100 厘米。此外,您将计算出电机旋转 90 度(正方形的角)需要多长时间。
一个示例程序example4.java
,展示了如何在 EV3 的莱霍斯使用MovePilot
描绘出一个正方形。
//************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 example4.java
//an example for tracing out a square
//************************************************************
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.ev3.EV3;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
import lejos.robotics.chassis.Chassis;
import lejos.robotics.chassis.Wheel;
import lejos.robotics.chassis.WheeledChassis;
import lejos.robotics.navigation.*;
public class example4 {
static EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
static EV3LargeRegulatedMotor RIGHT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.C);
public static void main(String[] args) throws Exception {
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displaying and Keys // class for buttons
Keys buttons = ev3brick.getKeys();
// block the thread until a button is pressed
buttons.waitForAnyPress();
// setup the wheel diameter of left (and right) // motor in centimeters,
// i.e. 2.8 cm
// the offset number is the distance between the // center of wheel to
// the center of robot, i.e. half of track width
Wheel wheel1 = WheeledChassis.modelWheel(LEFT_MOTOR, 2.8).offset(-9);
Wheel wheel2 =
WheeledChassis.modelWheel(RIGHT_MOTOR, 2.8).offset(9);
// set up the chassis type, i.e. Differential pilot
Chassis chassis = new WheeledChassis(new Wheel[] { wheel1, wheel2 },
WheeledChassis.TYPE_DIFFERENTIAL);
MovePilot pilot = new MovePilot(chassis);
// loop 4 times to trace out a square
for (int sides = 0; sides < 4; sides++) {
// travel 100 centimeter
pilot.travel(100);
// rotate 90 degrees
pilot.rotate(90);
}
// press the ESCAPE button to stop moving
while (pilot.isMoving()) {
if (buttons.getButtons() == Keys.ID_ESCAPE)
pilot.stop();
}
// block the thread until a button is pressed
buttons.waitForAnyPress();
}
}
如果您使用 leJOS NXJ,下面的示例程序example5.java
将说明如何使用DifferentialPilot
类中提供的一组方法描绘出一个正方形。这背后的想法是基于基准测试,该测试显示车辆可以以 30.76 厘米/秒的速度向前行驶。相应地,车辆需要行驶 3.25 秒来完成正方形的一边。为了实现这一点,我们应用了一个sleep
函数,该函数从机器人向前移动开始,等待 3.25 秒,然后停止。评估程序的实验结果表明,该算法比直接使用DifferentialPilot
类的方法更有效。
//***************************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 example5.java
//an example for tracing out a square using DifferentialPilot in //leJOS NXJ
//***************************************************************************
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.Motor;
import lejos.nxt.NXTRegulatedMotor;
import lejos.robotics.navigation.DifferentialPilot;
import lejos.util.Stopwatch;
public class example5 {
// The vehicle's rate of travel forward in centimeters per
// second
private static final double FW_SPEED = 30.666666667f;
// The vehicle's clockwise rotation speed in degrees per
// second
private static final double ROTATION_SPEED = 248.297752809f;
// The vehicle's wheel-width.
private static final double WHEEL_DIAMETER = 3.1;
// The vehicle's width
private static final double TRACK_WIDTH = 17.5;
// Reference to left motor
private static NXTRegulatedMotor LEFT_MOTOR = Motor.A;
// Reference to right motor
private static NXTRegulatedMotor RIGHT_MOTOR = Motor.C;
/**
* The main entry point for the program.
*/
public static void main(String[] args) {
// construct the pilot using the static variables
DifferentialPilot pilot = new DifferentialPilot(WHEEL_DIAMETER,
TRACK_WIDTH, LEFT_MOTOR, RIGHT_MOTOR, false);
// tracing out a square
drawSquare(pilot, 100);
LCD.drawString("tracing is done, press button to exit.", 0, 0);
Button.waitForPress();
}
/**
* Draws a square of the specified side length
*
* @param pilot
* The pilot to use when drawing the square
* @param sideLength
* The length of each leg of the square
*/
public static void drawSquare(DifferentialPilot pilot, double sideLength) {
for (int i = 0; i < 4; i++) {
// delay 500ms to allow the motors to stabilize
sleep(500);
// move the vehicle forward
forward(pilot, sideLength);
// delay 500ms to allow the motors to stabilize
sleep(500);
// rotate the vehicle by 90 degrees to prepare
// for
// the next side of the square
rotate(pilot, 90);
}
}
/**
* Move the vehicle forward the specified distance
*
* @param pilot
* The pilot to use for moving forward
* @param distance
* The distance to travel
*/
public static void forward(DifferentialPilot pilot, double distance) {
// get the number of milliseconds the vehicle should
// travel based on the
// vehicle's speed
int travelTime = getMillisForTravel(distance);
// begin the pilot forward
pilot.forward();
// wait for the traveling to finish
sleep(travelTime);
// reached the destination - stop
pilot.stop();
}
/**
* Rotate the vehicle by the specified angle. Positive angles * will result in
* a clockwise rotation. Negative angles will result in a
* counterclockwise
* rotation.
*
* @param pilot
* @param angle
* The angle (in degrees) by which to rotate the
* vehicle
*/
public static void rotate(DifferentialPilot pilot, double angle) {
// determine the number of milliseconds to rotate based // on the vehicle
// speed
int travelTime = getMillisForRotate(angle);
// for negative angles, rotate counterclockwise
if (angle < 0)
pilot.rotateLeft();
else
// for positive angles, rotate clockwise
pilot.rotateRight();
// block the thread until the motion is complete
sleep(travelTime);
pilot.stop();
}
/**
* Gets the milliseconds to travel for a given travel distance
*
* @param distance
* The distance in centimeters to travel
* @return Returns the number of milliseconds to travel
*/
public static int getMillisForTravel(double distance) {
return (int) ((distance / FW_SPEED) * 1000);
}
/**
* Gets the milliseconds to rotate for the specified number of * degrees
*
* @param rotateDegree
* @return the number of milliseconds to rotate
*/
public static int getMillisForRotate(double rotateDegree) {
return (int) ((rotateDegree / ROTATION_SPEED) * 1000);
}
/**
* Sleep function using Thread.yield rather than thread.sleep
*
* @param millis
* The number of milliseconds to block the
* executing thread
*/
public static void sleep(long millis) {
// create the stopwatch
Stopwatch sw = new Stopwatch();
// continue waiting while the elapsed time is less than // the time
// specified
while (sw.elapsed() < millis)
Thread.yield();
}
}
描绘出一个等边三角形
在本节中,您将开发一个程序来创建一个机器人,该机器人可以描绘出一个等边三角形,其预定边长设置为 1 米。您将编写、编译并上传您的代码到 Lego Mindstorms。一个示例程序,example6.java
,展示了如何在 EV3 的莱霍斯使用MovePilot
描绘出一个等边三角形。
//******************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 example6.java
//an example for tracing out an equilateral triangle
//******************************************************************
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.ev3.EV3;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
import lejos.robotics.chassis.Chassis;
import lejos.robotics.chassis.Wheel;
import lejos.robotics.chassis.WheeledChassis;
import lejos.robotics.navigation.*;
public class example6 {
static EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
static EV3LargeRegulatedMotor RIGHT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.C);
public static void main(String[] args) throws Exception {
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displaying and Keys class // for buttons
Keys buttons = ev3brick.getKeys();
// block the thread until a button is pressed
buttons.waitForAnyPress();
// setup the wheel diameter of left (and right) motor // in centimeters,
// i.e. 2.8 cm
// the offset number is the distance between the center // of wheel to
// the center of robot, i.e. half of track width
Wheel wheel1 = WheeledChassis.modelWheel(LEFT_MOTOR, 2.8).offset(-9);
Wheel wheel2 = WheeledChassis.modelWheel(RIGHT_MOTOR, 2.8).offset(9);
// set up the chassis type, i.e. Differential pilot
Chassis chassis = new WheeledChassis(new Wheel[] { wheel1, wheel2 },
WheeledChassis.TYPE_DIFFERENTIAL);
MovePilot pilot = new MovePilot(chassis);
// loop 3 times to trace out an equilateral triangle
for (int sides = 0; sides < 3; sides++) {
// travel 100 centimeter
pilot.travel(100);
// rotate 120 degrees
pilot.rotate(120);
}
// press the ESCAPE button to stop moving
while (pilot.isMoving()) {
if (buttons.getButtons() == Keys.ID_ESCAPE)
pilot.stop();
}
// block the thread until a button is pressed
buttons.waitForAnyPress();
}
}
如果您使用 leJOS NXJ,下面的示例程序example7.java
将说明如何使用DifferentialPilot
类中提供的一组方法描绘出一个三角形。
//******************************************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 example7.java
//an example for tracing out an equilateral triangle using //DifferentialPilot in leJOS NXJ
//******************************************************************************************
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.Motor;
import lejos.nxt.NXTRegulatedMotor;
import lejos.robotics.navigation.DifferentialPilot;
import lejos.util.Stopwatch;
public class example7 {
// The vehicle's rate of travel forward in centimeters per
// second
private static final double FW_SPEED = 30.666666667f;
// The vehicle's clockwise rotation speed in degrees per
// second
private static final double ROTATION_SPEED = 248.297752809f;
// The vehicle's wheel-width.
private static final double WHEEL_DIAMETER = 3.1;
// The vehicle's track width
private static final double TRACK_WIDTH = 17.5;
// Reference to left motor
private static NXTRegulatedMotor LEFT_MOTOR = Motor.A;
// Reference to right motor
private static NXTRegulatedMotor RIGHT_MOTOR = Motor.C;
/**
* The main entry point for the program.
*/
public static void main(String[] args) {
// construct the pilot using the static variables
DifferentialPilot pilot = new DifferentialPilot(WHEEL_DIAMETER,
TRACK_WIDTH, LEFT_MOTOR, RIGHT_MOTOR, false);
// tracing out a triangle
drawTriangle(pilot, 100);
LCD.drawString("tracing is done, press button to exit.", 0, 0);
Button.waitForPress();
}
/**
* Draw an equilateral triangle
*
* @param pilot
* The pilot to use to draw the triangle
* @param sideLengthCm
* The side length of the triangle
*/
public static void drawTriangle(DifferentialPilot pilot, double sideLength) {
// iterate through the sides of the triangle
for (int i = 0; i < 3; i++) {
sleep(500);
// travel along a side
forward(pilot, sideLength);
sleep(500);
// re-orient to travel along the next side
rotate(pilot, 120);
}
}
/**
* Move the vehicle forward the specified distance
*
* @param pilot
* The pilot to use for moving forward
* @param distance
* The distance to travel
*/
public static void forward(DifferentialPilot pilot, double distance) {
// get the number of milliseconds the vehicle should
// travel based on the
// vehicle's speed
int travelTime = getMillisForTravel(distance);
// begin the pilot forward
pilot.forward();
// wait for the traveling to finish
sleep(travelTime);
// reached the destination - stop
pilot.stop();
}
/**
* Rotate the vehicle by the specified angle. Positive angles
* will result in
* a clockwise rotation. Negative angles will result in a
* counterclockwise
* rotation.
*
* @param pilot
* @param angle
* The angle (in degrees) by which to rotate the vehicle
*/
public static void rotate(DifferentialPilot pilot, double angle) {
// determine the number of milliseconds to rotate based
// on the vehicle
// speed
int travelTime = getMillisForRotate(angle);
// for negative angles, rotate counterclockwise
if (angle < 0)
pilot.rotateLeft();
else
// for positive angles, rotate clockwise
pilot.rotateRight();
// block the thread until the motion is complete
sleep(travelTime);
pilot.stop();
}
/**
* Gets the milliseconds to travel for a given travel distance
*
* @param distance
* The distance in centimeters to travel
* @return Returns the number of milliseconds to travel
*/
public static int getMillisForTravel(double distance) {
return (int) ((distance / FW_SPEED) * 1000);
}
/**
* Gets the milliseconds to rotate for the specified number of
* degrees
*
* @param rotateDegree
* @return the number of milliseconds to rotate
*/
public static int getMillisForRotate(double rotateDegree) {
return (int) ((rotateDegree / ROTATION_SPEED) * 1000);
}
/**
* Sleep function using Thread.yield rather than thread.sleep
*
* @param millis
* The number of milliseconds to block the executing thread
*/
public static void sleep(long millis) {
// create the stopwatch
Stopwatch sw = new Stopwatch();
// continue waiting while the elapsed time is less than // the time
// specified
while (sw.elapsed() < millis)
Thread.yield();
}
}
描绘出一个正六边形
在本节中,您将开发一个程序来创建一个机器人,该机器人可以描绘出一个边长预定为 50 厘米的正六边形。您将编写、编译并上传您的代码到 Lego Mindstorms。一个示例程序example8.java
,展示了如何在 EV3 的莱霍斯使用MovePilot
描绘出一个正六边形。
//************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 example8.java
//an example for tracing out a regular hexagon
//************************************************************
import lejos.hardware.BrickFinder;
import lejos.hardware.Keys;
import lejos.hardware.ev3.EV3;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
import lejos.robotics.chassis.Chassis;
import lejos.robotics.chassis.Wheel;
import lejos.robotics.chassis.WheeledChassis;
import lejos.robotics.navigation.*;
public class example8 {
static EV3LargeRegulatedMotor LEFT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.A);
static EV3LargeRegulatedMotor RIGHT_MOTOR = new EV3LargeRegulatedMotor(MotorPort.C);
public static void main(String[] args) throws Exception {
// get EV3 brick
EV3 ev3brick = (EV3) BrickFinder.getLocal();
// instantiated LCD class for displaying and Keys // class for buttons
Keys buttons = ev3brick.getKeys();
// block the thread until a button is pressed
buttons.waitForAnyPress();
// setup the wheel diameter of left (and right) // motor in centimeters,
// i.e. 2.8 cm
// the offset number is the distance between the // center of wheel to
// the center of robot, i.e. half of track width
Wheel wheel1 = WheeledChassis.modelWheel(LEFT_MOTOR, 2.8).offset(-9);
Wheel wheel2 = WheeledChassis.modelWheel(RIGHT_MOTOR, 2.8).offset(9);
// set up the chassis type, i.e. Differential
// pilot
Chassis chassis = new WheeledChassis(new Wheel[] { wheel1, wheel2 },
WheeledChassis.TYPE_DIFFERENTIAL);
MovePilot pilot = new MovePilot(chassis);
// loop 6 times to trace out a regular hexagon
for (int sides = 0; sides < 6; sides++) {
// travel 100 centimeter
pilot.travel(50);
// rotate 60 degrees
pilot.rotate(60);
}
// press the ESCAPE button to stop moving
while (pilot.isMoving()) {
if (buttons.getButtons() == Keys.ID_ESCAPE)
pilot.stop();
}
// block the thread until a button is pressed
buttons.waitForAnyPress();
}
}
如果你使用 leJOS NXJ,这里提供了一个示例程序example9.
java
来说明如何使用DifferentialPilot
类中提供的一组方法描绘出一个六边形。
//******************************************************************
//Wei Lu Java Robotics Programming with Lego EV3 example9.java
//an example for tracing out a regular hexagon using //DifferentialPilot in leJOS NXJ
//******************************************************************
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.Motor;
import lejos.nxt.NXTRegulatedMotor;
import lejos.robotics.navigation.DifferentialPilot;
import lejos.util.Stopwatch;
public class example9 {
// The vehicle's rate of travel forward in centimeters per
// second
private static final double FW_SPEED = 30.666666667f;
// The vehicle's clockwise rotation speed in degrees per
// second
private static final double ROTATION_SPEED = 248.297752809f;
// The vehicle's wheel-width.
private static final double WHEEL_DIAMETER = 3.1;
// The vehicle's wheel-bas
private static final double TRACK_WIDTH = 17.5;
// Reference to left motor
private static NXTRegulatedMotor LEFT_MOTOR = Motor.A;
// Reference to right motor
private static NXTRegulatedMotor RIGHT_MOTOR = Motor.C;
/**
* The main entry point for the program.
*/
public static void main(String[] args) {
// construct the pilot using the static variables
DifferentialPilot pilot = new DifferentialPilot(WHEEL_DIAMETER,
TRACK_WIDTH, LEFT_MOTOR, RIGHT_MOTOR, false);
// tracing out a triangle
drawHexagon(pilot, 50);
LCD.drawString("tracing is done, press button to exit.", 0, 0);
Button.waitForPress();
}
/**
* Draw a hexagon with sides of the specified length
*
* @param pilot
* The pilot to use for drawing the hexagn
* @param sideLengthCm
* The length of each side of the regular hexagon
*/
public static void drawHexagon(DifferentialPilot pilot, double sideLength) {
// iterate through the sides of the hexagon
for (int i = 0; i < 6; i++) {
sleep(500);
// move the vehicle along an edge
forward(pilot, sideLength);
sleep(500);
// rotate the bot to traverse the next leg
rotate(pilot, 60);
}
}
/**
* Move the vehicle forward the specified distance
*
* @param pilot
* The pilot to use for moving forward
* @param distance
* The distance to travel
*/
public static void forward(DifferentialPilot pilot, double distance) {
// get the number of milliseconds the vehicle should
// travel based on the
// vehicle's speed
int travelTime = getMillisForTravel(distance);
// begin the pilot forward
pilot.forward();
// wait for the traveling to finish
sleep(travelTime);
// reached the destination - stop
pilot.stop();
}
/**
* Rotate the vehicle by the specified angle. Positive angles
* will result in
* a clockwise rotation. Negative angles will result in a
* counterclockwise
* rotation.
*
* @param pilot
* @param angle
* The angle (in degrees) by which to rotate the vehicle
*/
public static void rotate(DifferentialPilot pilot, double angle) {
// determine the number of milliseconds to rotate based // on the vehicle
// speed
int travelTime = getMillisForRotate(angle);
// for negative angles, rotate counterclockwise
if (angle < 0)
pilot.rotateLeft();
else
// for positive angles, rotate clockwise
pilot.rotateRight();
// block the thread until the motion is complete
sleep(travelTime);
pilot.stop();
}
/**
* Gets the milliseconds to travel for a given travel distance
*
* @param distance
* The distance in centimeters to travel
* @return Returns the number of milliseconds to travel
*/
public static int getMillisForTravel(double distance) {
return (int) ((distance / FW_SPEED) * 1000);
}
/**
* Gets the milliseconds to rotate for the specified number of
* degrees
*
* @param rotateDegree
* @return the number of milliseconds to rotate
*/
public static int getMillisForRotate(double rotateDegree) {
return (int) ((rotateDegree / ROTATION_SPEED) * 1000);
}
/**
* Sleep function using Thread.yield rather than thread.sleep
*
* @param millis
* The number of milliseconds to block the
* executing thread
*/
public static void sleep(long millis) {
// create the stopwatch
Stopwatch sw = new Stopwatch();
// continue waiting while the elapsed time is less than // the time
// specified
while (sw.elapsed() < millis)
Thread.yield();
}
}
摘要
在这一章中,你学习了 leJOS EV3 的MovePilot
类和 leJOS NXJ 的DifferentialPilot
类中提供的各种方法。基于这些方法,你现在知道如何精确地控制轮式车辆的运动。具体来说,九个 Java leJOS 示例项目详细说明了如何使用 Lego Mindstorms EV3 和 Lego Mindstorms NXT 的 pilot 类描绘出具有预定义长度的边的预定义几何形状。
在下一章中,你将学习到在 EV3 使用的笛卡尔坐标系的基础知识。然后,在此基础上,你将学习如何在导航课程中应用编程方法来控制轮式车辆,以便在二维平面中用坐标描绘出预定义的路径。此外,还将介绍乐高 EV3 积木的主要硬件组件。