原文:Beginning Robotics Programming in Java with LEGO Mindstorms
本章包括如何在你的计算机上安装莱霍斯 EV3 开发系统,如何在乐高 EV3 积木上安装莱霍斯 EV3 固件,以及如何安装和应用 Eclipse IDE 的莱霍斯 EV3 插件。最后,您将创建第一个名为 HelloWorld 的 Java 机器人程序,通过 USB 电缆将 HelloWorld 程序从您的计算机上传到乐高 EV3 积木中,并在乐高 Mindstorms EV3 上执行该程序。
乐高 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 找到。
“leJOS”的意思是 Lego for Java 操作系统,这是一种开源语言,用于使用 Java 技术为 Lego Mindstorms 产品开发软件。leJOS 项目支持乐高 MindStorm EV3,以及以前的版本,包括乐高 MindStorm NXT 和乐高 MindStorm RCX。leJOS 项目为 Lego Mindstorms 提供了以下解决方案:
在这本书里,我们关注的是最新的乐高 MindStorm 产品:也就是乐高 MindStorm EV3。表 1-1 显示了 leJOS 为 EV3 砖提供的典型官方包装。这些软件包允许你管理 EV3 砖,传感器,执行器,以及其他一些 EV3 硬件。
表 1-1。
EV3 brick packages
| 包裹 | 描述 |表 1-2 列出了为一些机器人问题提供支持的包,比如定位和导航。
Robotics/AI packages
| 包裹 | 描述 || --- | --- |
| lejos .机器人.本地化 | 本地化支持 |所有 leJOS 版本都有 Javadoc 格式的包文档。有关 EV3 莱霍斯酒店提供的套餐详情,请访问: http://www.lejos.org/ev3/docs/ 。
图 1-2 显示了莱霍斯 EV3 开发文件。
图 1-2。
leJOS development documents
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 filejdk-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 pathC:\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 程序。
在您的计算机上打开一个 Shell 控制台,并键入命令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
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-clickleJOS_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 andJAVA_HOMEto 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 calledleJOS 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.gzfile. 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.
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 砖中。
当然,仅仅使用文本编辑器和命令行也可以进行 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,因为leJOS·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, selectHelp > 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 theEV3_HOMEenvironment variable to locate leJOS EV3. Check to make sure that the preferences are what you like. SelectWindows -> Preferencesand 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 , entertestand 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, selectFile > New > Class. EnterHelloWorldin 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 和leJOS系统,并使用外部 SD 卡在乐高 MindStorm EV3 积木上刻录leJOS EV3 固件。您还使用 leJOS 和您的机器人运行了第一个名为HelloWorld的 Java 机器人程序。leJOS 可以安装在主流的操作系统中,比如 Windows、Linux 和 Mac OS。特别是,您在本章中学到了以下内容:
在下一章中,您将了解 EV3 大型电机及其在leJOS EV3 提供的相应电机类别。然后,在此基础上,你将学习如何使用电机控制基本运动,如何中断旋转,如何调节电机速度,以及如何跟踪直线。
本章介绍了 EV3 大型伺服电机及其在 EV3 莱霍斯提供的相应电机类别。特别是,本章包括六个示例 Java 项目,涵盖以下主题:
leJOS 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 列打印一个文本字符串。 |
该程序应该执行以下操作:
以下程序实现了上面定义的电机运动:
//***************************************************************
//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 大型伺服电机有一个内置的转速表,跟踪电机轴的当前角度(以度为单位)。该程序的目的是使用转速表找出电机停止的速度。
该程序应该执行以下操作:
由于马达的惯性,你会发现在你调用方法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)` | 旋转到指定的角度。 |
该程序应该执行以下操作:
根据电机调节器,电机通常在距指定角度不到 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 号。 |
该程序应该执行以下操作:
当您在旋转完成前按下按钮时,电机将停止旋转。
//************************************************************
//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
| | | 功能 |秒表类包含在包lejos.util.Stopwatch中。该程序应该执行以下操作:
根据你的观察,这些电机应该保持在几度之内,因为我们使用了调节的大型电机 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 毫秒),并测量机器人行进的距离。该程序应该执行以下操作:
重复你的程序三次,然后计算一个距离与时间的平均比,就是机器人的速度。
//******************************************************************
//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
| 方法 | 功能 |在这一章中,你学习了 EV3 电机的特点:电机如何旋转,如何设置电机的速度,以及速度调节的基本思想。具体来说,通过使用本章中提供的六个 Java leJOS 项目示例,您学习了如何编写和应用 leJOS Java 编程代码来控制和操作 Lego Mindstorms EV3 汽车。
在下一章中,你将会了解到在莱霍斯 next 的试点课程中提供的各种方法。您还将学习如何应用这些方法来控制轮式车辆,以便它可以描绘出具有预定长度的边的预定几何形状,包括正方形、三角形和六边形。
本章介绍了 EV3 的 MovePilot 类中提供的各种方法。你将在飞行员课程中学习如何应用这些方法来控制轮式车辆,使其能够描绘出具有预定长度的边的预定几何形状,包括正方形、三角形和六边形。具体来说,本章包括九个示例 Java 项目,并涵盖以下主题:
你在第二章中学习了如何为 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();
通常,如果您只是使用一个独特的电机,您可以使用的方法如下:
在实际使用中,车辆通常配备两个车轮,由两个电机独立控制和导航。这种导航是通过 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类的一些核心方法包括:
接下来,您将了解如何使用物理机器人来执行这些动作。在 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)
总之,为了控制机器人沿直线运动,可以使用以下方法:
为了控制机器人移动的距离,可以使用以下方法:
例如,下面的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 积木的主要硬件组件。
来源:https://juejin.cn/post/7399898613704933411
结构化程序设计是采用顺序结构、选择结构(IF语句)、循环结构(FOR,WHILE语句)、子程序等来进行程序设计的一种编程典范。
本文介绍如何在Scratch中对EV3机器人进行开发。
在这一章中,你将学习一组传感器,它们被用来执行有根据的动作。
在本章中,您将学习启发式搜索策略背后的基本思想以及如何实现爬山算法,这是 leJOS EV3 中最典型的启发式方法之一。
这一章向你介绍了在莱霍斯 EV3 使用的笛卡尔坐标系的基础知识。它还教你如何在导航课程中应用编程方法来控制轮式车辆,以便在二维平面中用坐标描绘出预定义的路径。
乐高EV3遥控车:从搭建到编程的全面指南