building smart dashboard with gradle

FRC (FIRST Robotics Challenge) uses Ant to build the robot code. I think this is a wise choice since some teams are “internet challenged.” This hasn’t changed. What has changed since last year is that SmartDashboard uses Gradle to build. Our team is thinking about customizing Smart Dashboard this year which means we need to be able to build it.

Yesterday in the FRC lab, one of the StuyPulse team members asked me about Gradle. (I gave a really good overview of Ant last year so they remembered I knew build tools.) I explained the concepts of Maven/Gradle especially the local repository and dependencies. And I verbally explained how to run it. We didn’t get to do so together as there were other priorities for the day. And a lot of people weren’t at the meeting due to a competing school event. So I’m writing everything down in this post.

Building Smart Dashboard

The discussion was centered around building SmartDashboard. If you aren’t involved with a FIRST Robotics Competition team, this is a Java based UI used when running the robot. Conveniently that project comes with Gradle right in the project. So all you have to is:

  1. cd to directory you cloned SmartDashboard in
  2. chmod 700 gradlew
  3. ./gradlew build

Make sure you have internet before running this the first time. If you want to build directly from Eclipse, see my Eclipse Gradle post

Where is the output when building SmartDashboard

Running gradle creates a build directory. If you are using Eclipse, remember to hit refresh before looking for it. This build directory  contains a number of things:

  • distributions – a zipped up and tarred up version of SmartDashboard which includes the jar file, all need dependencies and the script to kick it off. This is what you need
  • classes – the compiled .class files
  • libs – a jar file with the compiled code in this project
  • reports – how well did you follow the coding standards established for this project
  • scripts – to launch SmartDashboard
  • temp – would you really expect to find something important in a directory named temp?

What does the Gradle build file do?
Gradle is a build tool. The build.gradle file in SmartDashboard contains Groovy code that declares what the build should do. Both Gradle and Maven follow “convention over configuration” which means that a lot is implied! I went over most (but not all) of this out loud in the classroom.

A plugin is like a helper tool that Gradle is going to use in order to build. For example, ‘java’ is going to compile among other things.  Most of these plugins are in common use. I hadn’t heard of the shadow before. A quick look tells me that it builds an uber jar (which is a distribution file that contains all the dependencies). That’s really useful. In fact, I have used the shade plugin which does the same thing in Maven. The WPILibVersioningPlugin is obviously specialized code for FIRST.

plugins {
    id 'java'
    id 'application'
    id 'com.github.johnrengelman.shadow' version '1.2.4'
    id 'maven-publish'
    id 'idea'
    id 'edu.wpi.first.wpilib.versioning.WPILibVersioningPlugin' version '1.6'
    id 'checkstyle'
}

Gradle needs to download files in order to run. This includes the plugins that we just saw along with dependencies – jars that the program needs. These files are hosted in a repository for binary files. A really common one is Maven Central. This is used by both Maven and Gradle builds to obtain binaries.

repositories {
    mavenCentral()
}

Those dependencies I just mentioned? Here they are. In this case, the dependencies are WPI code and common open source tools like JUnit (a testing library). Notice how all of these except the WPI one use the same format – three strings separated by colons? There’s a reason for this. When accessing Maven Central, you specify a GAV. This stands for group id/artifact id/version. The colons separate them. For example, jfree is a group id, jfreechart is an artifact id and 1.0.13 is a version.

Note that none of these four exhibits a “normal” GAV. You are supposed to use a fully qualified name for the group id. Just like we do for Java package names. An artifact id is lower case “words” separated by dashes if there is more than one word. Finally, you have an optional version number.  There can also be some optional information like a classifier that tells you what file extension you need. The WPI example does have a good group id. And the others have good artifact ids and versions. For more on the WPILib group id see this post.

dependencies {
    compile 'edu.wpi.first.wpilib.networktables.java:NetworkTables:+:desktop'
    compile 'junit:junit:4.12'
    compile 'jfree:jcommon:1.0.16'
    compile 'jfree:jfreechart:1.0.13'
}

Next the script specifies that we should create a jar file and an uber jar file named SmartDashboard.

jar {
    baseName = 'SmartDashboard'
}
shadowJar {
    baseName = 'SmartDashboard'
}

Now you see that this really is a Groovy script; it even has an if statement.

// Ensure that the WPILibVersioningPlugin is setup by setting the release type, if releaseType wasn't
// already specified on the command line
if (!hasProperty('releaseType')) {
    WPILibVersion {
        releaseType = 'dev'
    }
}

If the artifact is being published, details are here. WPI is publishing to this FIRST WPI Maven repo. They use the WPI Version Plugin and publish to the local Maven repo – which is the FIRST WPI Maven repo on their build server. (clarified in comment 65)

publishing {
    publications {
        maven(MavenPublication) {
            artifact(shadowJar) {
                classifier null
            }
            groupId 'edu.wpi.first.wpilib'
            artifactId 'SmartDashboard'
            version WPILibVersion.version
        }
    }
}

Getting close to the end. Now the build configuration says to use the coding conventions in the checkstyle.xml file. This is good. It means that people will have to follow coding conventions if they contribute back to SmartDashboard.

checkstyle {
    configFile = new File(rootDir, "checkstyle.xml")
    toolVersion = '6.19'
    if (project.hasProperty("ignoreCheckstyle")) {
        ignoreFailures = true
    }
}

In Java, you can automatically configure a Jar to run a certain class’ main method when you run the jar. This is specified in the manifest. Gradle can generate this manifest for you.

mainClassName = "edu.wpi.first.smartdashboard.SmartDashboard"

SmartDashboard comes with a fakeRobot test project. This is a submodule from Gradle’s point of view so it needs a build config too. Luckily you already know what plugins, dependencies and a main class are so this should be clear.

project(':fakeRobot') {
  apply plugin: 'java'
  apply plugin: 'application'

  dependencies {
      compile 'edu.wpi.first.wpilib.networktables.java:NetworkTables:+:desktop'
  }

  mainClassName = "edu.wpi.livewindowfakerobot.LiveWindowFakeRobot"
}

The end! The very last thing is to declare which version of Gradle this entire script should be run with.

task wrapper(type: Wrapper) {
    gradleVersion = '3.3'
}
  1.  

Output from building in gradle

I’m including the output from a “good” run in case you have problems and want to compare. This is for the first time you run it. After that the download steps won’t be in the output and it will run much faster.

$ ./gradlew build
Downloading https://services.gradle.org/distributions/gradle-3.3-bin.zip
..................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Unzipping /Users/jeanne/.gradle/wrapper/dists/gradle-3.3-bin/64bhckfm0iuu9gap9hg3r7ev2/gradle-3.3-bin.zip to /Users/jeanne/.gradle/wrapper/dists/gradle-3.3-bin/64bhckfm0iuu9gap9hg3r7ev2
Set executable permissions for: /Users/jeanne/.gradle/wrapper/dists/gradle-3.3-bin/64bhckfm0iuu9gap9hg3r7ev2/gradle-3.3/bin/gradle
Starting a Gradle Daemon (subsequent builds will be faster)
Download https://plugins.gradle.org/m2/com/github/jengelman/gradle/plugins/shadow/1.2.4/shadow-1.2.4.pom
Download https://plugins.gradle.org/m2/gradle/plugin/edu/wpi/first/wpilib/versioning/wpilib-version-plugin/1.6/wpilib-version-plugin-1.6.pom
Download https://plugins.gradle.org/m2/org/ow2/asm/asm-commons/5.0.3/asm-commons-5.0.3.pom
Download https://plugins.gradle.org/m2/org/apache/ant/ant/1.9.4/ant-1.9.4.pom
Download https://plugins.gradle.org/m2/org/apache/ant/ant-parent/1.9.4/ant-parent-1.9.4.pom
Download https://plugins.gradle.org/m2/org/codehaus/groovy/groovy-backports-compat23/2.4.4/groovy-backports-compat23-2.4.4.pom
Download https://plugins.gradle.org/m2/org/ajoberstar/grgit/1.7.0/grgit-1.7.0.pom
Download https://plugins.gradle.org/m2/org/apache/ant/ant-launcher/1.9.4/ant-launcher-1.9.4.pom
Download https://plugins.gradle.org/m2/org/eclipse/jgit/org.eclipse.jgit/4.3.1.201605051710-r/org.eclipse.jgit-4.3.1.201605051710-r.pom
Download https://plugins.gradle.org/m2/org/eclipse/jgit/org.eclipse.jgit-parent/4.3.1.201605051710-r/org.eclipse.jgit-parent-4.3.1.201605051710-r.pom
Download https://plugins.gradle.org/m2/org/eclipse/jgit/org.eclipse.jgit.ui/4.3.1.201605051710-r/org.eclipse.jgit.ui-4.3.1.201605051710-r.pom
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.jsch/0.0.9/jsch.agentproxy.jsch-0.0.9.pom
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy/0.0.9/jsch.agentproxy-0.0.9.pom
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.pageant/0.0.9/jsch.agentproxy.pageant-0.0.9.pom
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.sshagent/0.0.9/jsch.agentproxy.sshagent-0.0.9.pom
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.usocket-jna/0.0.9/jsch.agentproxy.usocket-jna-0.0.9.pom
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.usocket-nc/0.0.9/jsch.agentproxy.usocket-nc-0.0.9.pom
Download https://plugins.gradle.org/m2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.pom
Download https://plugins.gradle.org/m2/org/slf4j/slf4j-parent/1.7.21/slf4j-parent-1.7.21.pom
Download https://plugins.gradle.org/m2/com/jcraft/jsch/0.1.53/jsch-0.1.53.pom
Download https://plugins.gradle.org/m2/com/googlecode/javaewah/JavaEWAH/0.7.9/JavaEWAH-0.7.9.pom
Download https://plugins.gradle.org/m2/org/sonatype/oss/oss-parent/5/oss-parent-5.pom
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.core/0.0.9/jsch.agentproxy.core-0.0.9.pom
Download https://plugins.gradle.org/m2/com/github/jengelman/gradle/plugins/shadow/1.2.4/shadow-1.2.4.jar
Download https://plugins.gradle.org/m2/gradle/plugin/edu/wpi/first/wpilib/versioning/wpilib-version-plugin/1.6/wpilib-version-plugin-1.6.jar
Download https://plugins.gradle.org/m2/org/ow2/asm/asm-commons/5.0.3/asm-commons-5.0.3.jar
Download https://plugins.gradle.org/m2/org/apache/ant/ant/1.9.4/ant-1.9.4.jar
Download https://plugins.gradle.org/m2/org/codehaus/groovy/groovy-backports-compat23/2.4.4/groovy-backports-compat23-2.4.4.jar
Download https://plugins.gradle.org/m2/org/ajoberstar/grgit/1.7.0/grgit-1.7.0.jar
Download https://plugins.gradle.org/m2/org/apache/ant/ant-launcher/1.9.4/ant-launcher-1.9.4.jar
Download https://plugins.gradle.org/m2/org/eclipse/jgit/org.eclipse.jgit/4.3.1.201605051710-r/org.eclipse.jgit-4.3.1.201605051710-r.jar
Download https://plugins.gradle.org/m2/org/eclipse/jgit/org.eclipse.jgit.ui/4.3.1.201605051710-r/org.eclipse.jgit.ui-4.3.1.201605051710-r.jar
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.jsch/0.0.9/jsch.agentproxy.jsch-0.0.9.jar
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.pageant/0.0.9/jsch.agentproxy.pageant-0.0.9.jar
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.sshagent/0.0.9/jsch.agentproxy.sshagent-0.0.9.jar
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.usocket-jna/0.0.9/jsch.agentproxy.usocket-jna-0.0.9.jar
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.usocket-nc/0.0.9/jsch.agentproxy.usocket-nc-0.0.9.jar
Download https://plugins.gradle.org/m2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar
Download https://plugins.gradle.org/m2/com/jcraft/jsch/0.1.53/jsch-0.1.53.jar
Download https://plugins.gradle.org/m2/com/googlecode/javaewah/JavaEWAH/0.7.9/JavaEWAH-0.7.9.jar
Download https://plugins.gradle.org/m2/com/jcraft/jsch.agentproxy.core/0.0.9/jsch.agentproxy.core-0.0.9.jar
No .git was found in /Users/jeanne/Documents/workspace/SmartDashboard, or any parent directories of that directory.
No version number generated.
:compileJava
Download http://first.wpi.edu/FRC/roborio/maven/development/edu/wpi/first/wpilib/networktables/java/NetworkTables/3.1.5-20170105171843-1-g3e2631f/NetworkTables-3.1.5-20170105171843-1-g3e2631f.pom
Download https://repo1.maven.org/maven2/jfree/jcommon/1.0.16/jcommon-1.0.16.pom
Download https://repo1.maven.org/maven2/jfree/jfreechart/1.0.13/jfreechart-1.0.13.pom
Download http://first.wpi.edu/FRC/roborio/maven/development/edu/wpi/first/wpilib/networktables/java/NetworkTables/3.1.5-20170105171843-1-g3e2631f/NetworkTables-3.1.5-20170105171843-1-g3e2631f-desktop.jar
Download https://repo1.maven.org/maven2/jfree/jcommon/1.0.16/jcommon-1.0.16.jar
Download https://repo1.maven.org/maven2/jfree/jfreechart/1.0.13/jfreechart-1.0.13.jar
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
:processResources UP-TO-DATE
:classes
:jar
:startScripts
:distTar
:distZip
:assemble
:checkstyleMain
Download https://repo1.maven.org/maven2/com/puppycrawl/tools/checkstyle/6.19/checkstyle-6.19.pom
Download https://repo1.maven.org/maven2/org/antlr/antlr4-runtime/4.5.3/antlr4-runtime-4.5.3.pom
Download https://repo1.maven.org/maven2/org/antlr/antlr4-master/4.5.3/antlr4-master-4.5.3.pom
Download https://repo1.maven.org/maven2/commons-cli/commons-cli/1.3.1/commons-cli-1.3.1.pom
Download https://repo1.maven.org/maven2/com/puppycrawl/tools/checkstyle/6.19/checkstyle-6.19.jar
Download https://repo1.maven.org/maven2/org/antlr/antlr4-runtime/4.5.3/antlr4-runtime-4.5.3.jar
Download https://repo1.maven.org/maven2/commons-cli/commons-cli/1.3.1/commons-cli-1.3.1.jar
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:checkstyleTest UP-TO-DATE
:test UP-TO-DATE
:check
:build
:fakeRobot:compileJava
:fakeRobot:processResources UP-TO-DATE
:fakeRobot:classes
:fakeRobot:jar
:fakeRobot:startScripts
:fakeRobot:distTar
:fakeRobot:distZip
:fakeRobot:assemble
:fakeRobot:compileTestJava UP-TO-DATE
:fakeRobot:processTestResources UP-TO-DATE
:fakeRobot:testClasses UP-TO-DATE
:fakeRobot:test UP-TO-DATE
:fakeRobot:check UP-TO-DATE
:fakeRobot:build

BUILD SUCCESSFUL

Total time: 1 mins 9.099 secs

why i’m so proud of frc team 694 and their cv in auton scoring

FRC Team 694, StuyPulse is currently competing at the China Robotics Challenge which is an off season event. The event uses the same game/challenge as the “main” season which ran from January 2016-April 2016. This year’s event was the Stronghold game. In the autonomous part of the game, you got points for going over obstacles (defenses) and/or shooting a ball into a target.  The team worked on CV (computer vision) very hard this year. This was going to be the year we used CV in competition.. We used it one year when a lot of the code was supplied to teams. And we got CV recognition working last year, but not soon enough to integrate with the robot. We did have a really cool demo where it automatically recognized a target but never quite got it fully working with the robot.

Which brings us to 2016. Don’t get me wrong, I’m thrilled that it worked. But that’s only a piece of why I’m so proud of what happened with CV this year

Subteam

There were dedicated team members who focused on CV for most of the build season. This wasn’t one student on a Skunkswork project. Making a subteam shows this is a priority. Something the team values and wants to see succeed.

Sustainablility/Continuity

There were students in different grades on the subteam. This will ensure that the knowledge and experiences gained won’t all graduate at the same time. Which allows this to become a skill that grows every year rather than having to start over.

Technical understanding

The last two years I’ve seen a marked increase in the deep understanding of how CV works. It isn’t just poking at it. This is hard stuff. Same for communication channels between the camera and the robot. Although I did enjoy the discussion about bit endian vs little endian on transferring data. I knew it was that because we had that problem in the past. So seeing it back, I recognized it faster. Convincing the student I was working with on the problem took a little longer ;).

Team Communication

Some years, I see mixed messages about CV. Whether it is the drivers not trusting it or other parts of the robot being higher priority, the messaging can become demoralizing to the people working on the code. This year, I felt like the whole team wanted to see this happen. There were designated windows to work on CV integration with the robot even really close to the robot’s due date. It wasn’t shafted. It wasn’t put on the back burner.

Quick response to change

There were a number of integration problems. The students quickly adjusted to each one trying different strategies.  And they learned what works/doesn’t work for next year too.

*Never* giving up

Whether it was between matches at competition or after we got eliminated at a competition, the students were working at various aspects of the robot. Even after it became apparent we weren’t going to run the CV during competition because the risk at Championships was too high, the students STILL didn’t give up. They made the most of practice field time to test. They kept testing and integrating and testing and… They *never* gave up and got it working.

At home, I have a Peanuts picture near my desk. It has Lucy holding the football and Charlie Brown looking at it with a caption “Never ever EVER give up.” This is really important. You never know when pushing just a little bit further is going to be the difference. And I’m so proud of them for that. Pushing past the point where most people would give up in a really important skill and just as important as tech skills.

Cookies and Chocolate

On “stop build” day, the team had come further than ever before with CV. The electronics mentor and I chipped in and bought cookies to give out at the “tagging ceremony.” (This is when the code gets tagged in github as the last code tested on the robot before ship date.) I spoke for a minute or so on how big a deal with was and issued a challenge. I would bring in “something better than cookies” if they scored a certain number of goals with CV in competition. A 9th grader said “there’s nothing better than cookies.”

This is the first year I believed it could happen. (Sorry Josh – there were too many forces against you.) While that didn’t happen it wasn’t because of not being able to do it. It was that the risk of getting eliminated at championships was too high by the time CV was reliable. It was the right call.

So at the end of year dinner, I extended the offer to include the China Robotics Championships. Where they scored in autonomous in two out of two practice matches. While the number of goals for my offer is higher than two, the repeatability of getting 100% of them in practice matches is enough for me to declare success for the contest.

Which bring us to – what is better than cookies. It’s not pizza. We eat too much pizza during the build season for that to be a reward for anything. Instead the answer is chocolate:

694-chocolate

694-candy

694-candy

Congratulations 694. I am so proud of you for this accomplishment. Both both the tech skills to do it and for the soft skills and tenacity. Great job!!!

[first] 2014 championship conference

Sometimes I blog about a conference when I attend it. Today, I attended a number of sessions at the 2014 First Championship Conference. It was my first time attending these talks. There was a good level of quality.