So, now we come to the task of the hour: writing a Hello, World program for EV3, which when executed, displays the string Hello, World on the LCD screen of EV3 and exits when any hardware button is pressed. We start by creating the project directory structure inside the lejos
top-level folder. We will create a HelloWorld
folder containing the ev3
subfolder, a src
subfolder, and the build.gradle
file. We add a HelloWorld.java
file to src
. The project's folder now looks as follows:
HelloWorld | ---- ev3 | | ---- DBusJava | | ---- ev3classes | | ---- build.gradle | | ---- src | ---- HelloWorld.java
Let's begin by taking a look at the HelloWorld.java
program in full and then I will explain it line by line:
import lejos.hardware.Button; import lejos.hardware.lcd.LCD; public class HelloWorld { public static void main(String[] args) { LCD.drawString("Hello, World", 2, 3); Button.waitForAnyPress(); } }
The first two lines of the program are:
import lejos.hardware.Button; import lejos.hardware.lcd.LCD;
These lines of code import two classes, Button
and LCD
, that are used later in the program. These classes are defined in the LeJOS API, and this is the reason why our code must be compiled with the LeJOS source code placed in the lejos/ev3
folder. The import is carried out using the package named lejos.hardware
. This identifies the package (the group of code) that the class belongs to as well as specifies the path of the class. If you look inside the lejos/ev3/ev3classes/src
folder, you will find that the Button
class is defined in the lejos/hardware/Button.java
file and the LCD
class is defined in lejos/hardware/lcd/LCD.java
.
Next, the program defines the main class of the project, HelloWorld
, inside which the main
function is defined (where the program begins its execution):
public class HelloWorld { public static void main(String[] args) {
The first line of the main
function is also the first line that makes use of the LeJOS API:
LCD.drawString("Hello, World", 2, 3);
We use the LCD
class and call its drawString
method, which prints the specified string, starting from the third column of the fourth row of characters, on the LCD screen (the positions are zero-indexed). We now want the execution to be paused until any hardware button is pressed:
Button.waitForAnyPress();
This function does exactly that. It waits for any hardware button to be pressed before the execution is allowed to move on to the next line. However, there is no next line; we have arrived at the end of the function (indicated by the closing curly brace) and, therefore, the end of the program.
So, in totality, the program clears the LCD, prints Hello, World on the screen, and waits for any hardware button to be pressed, after which the LCD is cleared and the program ends.
With the Java source code in hand, we are now ready to compile it in order to create an executable .jar
file, which we will run on EV3. We will use Gradle to compile the code, which requires us to write the following build.gradle
file:
apply plugin: 'java' def main_class = "HelloWorld" sourceSets { main { java { srcDirs = ['src', 'ev3/DBusJava/src', 'ev3/ev3classes/src'] } dependencies { compile files('ev3/ev3classes/lib/jna-3.2.7.jar') } jar { manifest { attributes("Main-Class" main_class, "Class-Path": "/home/root/lejos/lib/ev3classes.jar /home/root/lejos/libjna/usr/share/java/jna.jar") } } } }
The first line, apply plugin: 'java'
, declares the plugin that Gradle will use, namely java
since the LeJOS programs are written in pure Java. The next line defines a variable named main_class
, which we use later in the build script:
def main_class = "HelloWorld"
A variable is declared using the def
keyword followed by an assignment. We set it up this way so that the build.gradle
file is reusable; simply change the value of the main_class
variable to the name of the main class in your project (in this case, HelloWorld
) and your build.gradle
file is ready to be used with your new project.
All the elements we need to override in the Java plugin are contained in the main sourceset; so, we create a main
section inside a sourceSets
section:
sourceSets { main {
The first entry declares all the directories containing the Java source code for the project:
java { srcDirs = ['src', 'ev3/DBusJava/src', 'ev3/ev3classes/src'] }
The directory paths are specified relative to the location of the build.gradle
file. If you look at the directory structure of the top-level lejos
folder, described in the previous section, the entries of the srcDirs
list become clear. First, we have the src
folder in the same folder as build.gradle
. This contains the HelloWorld.java
file we just wrote.
The next two entries tell Gradle that it will find the Java source code inside the ev3/DBusJava/src
and ev3/ev3classes/src
folders. This is how Gradle knows where to find the Button
and LCD
classes we use in HelloWorld.java
.
Next, we define the dependencies used by the project:
dependencies { compile files('ev3/ev3classes/lib/jna-3.2.7.jar') }
The LeJOS API uses the code library in the jna
JAR file; so, we need to specify it as a dependency. In the final section, we specify the key-value attribute pairs that we want included in the MANIFEST-MF
file that will be included in the generated program's .jar
file:
jar { manifest { attributes("Main-Class" main_class, "Class-Path": "/home/root/lejos/lib/ev3classes.jar /home/root/lejos/libjna/usr/share/java/jna.jar") } }
Two attributes are set. The first attribute is Main-Class
, which is given the value stored in the main_class
Gradle variable (in this case, HelloWorld
). This tells the program which class in the source code is the main one; the one containing the main()
function where program execution is supposed to start.
The second attribute is Class-Path
whose value is set to a string containing the locations of the necessary .jar
files separated by spaces. These .jar
files contain classes needed by LeJOS programs. The path specified is the absolute path on EV3 (running LeJOS); hence, the paths start with /home/root/lejos
.
This completes the Gradle build file which is now ready to compile the source code into an executable .jar
file that will run on EV3.
To compile the code, navigate to the HelloWorld
folder (which contains the build.gradle
file) and run gradle build
. Gradle will declare BUILD SUCCESSFUL
if the compilation is successful. A build
subfolder will be created. You will find the executable .jar
file at build/libs/HelloWorld.jar
.
Deploying the program (the executable .jar
file) to EV3 simply consists of copying the .jar
file into the /home/lejos/programs
folder on EV3's SD card. One method is to do just this: insert the SD card into your computer and copy the file directly into the SD card.
Or, if you have successfully set up SSH, you can use the scp
utility to copy the file. From the HelloWorld
folder on your computer (in a terminal, of course), run the following command:
scp build/libs/HelloWorld.jar ev3:/home/lejos/programs/
Now for the grand finale. On EV3, navigate to the Files menu and press Enter. You will see the HelloWorld.jar
file listed. Select it and press Enter. A number of options will be listed, but we are currently interested in only one: Execute program. Since it is selected by default, simply press Enter to run the program.
The screen immediately goes blank, but EV3 takes a few seconds to start the program. Once it does, you will see the fabled Hello, World string on the screen. When you are done gazing at it with a sense of tremendous accomplishment, press any key to exit the program and EV3 will return to the Files menu.
13.58.39.23