Beargineers logo

#27628

Beargineers

Telemetry

Driver Station lines, live graphs in the browser, logs, commands that start actions from a laptop, and the robot's web pages.

Driver Station lines

Opmodes and parts of the robot show lines on the Driver Station:

show("Intake", intake.mode)                                   // Intake: ON
show("Pose") { localizer.pose }                               // computed only when lines are sent
show("Press A to start the intake")                           // a line of its own

A line is shown for the loop it was shown in, so code that shows something does it every loop, in everyTick or a part’s update(). Loops are much faster than anyone can read, so lines are only collected every telemetry.updateInterval (100 ms): in the loops between, show() does nothing and values are never turned into text. For a value that is costly to make, pass a block, like the pose above: it runs only in loops that collect lines.

The Driver Station’s first lines are the platform’s own: how long loops take, like Loop: 2.4 ms average, 6.1 ms longest, and the battery, like Battery: 12.6 V, lowest 12.1 V.

Graphs

graph(name, value) records a number for the robot’s live graphs:

graph("shooter rpm", shooter.motor.velocity.inRpm)
graph("target rpm", targetRpm)

With the laptop on the robot’s WiFi, http://192.168.43.1:8080/bear/graphs draws them, one chart per value, and shows the Driver Station lines next to them. It needs no internet, and it keeps showing the last opmode after it stops. Graphs keep the last 30 seconds or so of every value, at most one sample per 10 ms.

The platform graphs some values itself: loop ms (every loop’s time, where a loop longer than 10 ms always shows up), battery, the robot’s pose (x cm, y cm, heading deg), and the path follower’s errors and powers.

Logs

log("...") writes a message to the robot’s log, from a part with the part’s path in front:

log("ball count reset")                                       // intake: ball count reset

The log also gets:

  • named steps: withName("Score") writes when a step starts, finishes, fails or gets cancelled (see Robot code over time);
  • the Driver Station lines, once a second (telemetry.logInterval), so a match’s log shows what the drivers saw;
  • warnings of the robot’s parts, settings problems, and the lowest battery voltage of the opmode.

The log is the SDK’s robot log: /sdcard/robotControllerLog.txt on the Control Hub, and logcat in Android Studio, where the platform’s lines carry the tag BearPlatform. FIRST’s match logs keep a copy for every match: http://192.168.43.1:8080/bear/matchLogs downloads them as a zip and deletes them from the robot.

Commands

For testing and tuning, an opmode can offer commands: actions started from a laptop, by buttons on the graphs page.

override suspend fun CoroutineScope.onStart() {
    command("forward 60 cm") { robot.follower.driveTo(Pose(60.cm, 0.cm, 0.degrees)) }
    command("open claw") { robot.claw.open() }
}

A command is offered as long as the code that offered it runs: commands offered in onInit go away at START, all of them when the opmode ends. Starting a command that still runs starts it over, like pressing a button again. Someone should be at the Driver Station, ready to stop the robot.

Scripts start commands too, with POST http://192.168.43.1:8080/bear/command?name=forward%2060%20cm, and read everything the graphs page shows, as JSON, from /bear/graphs/data: together they let a script run a drive, read what the robot did, change settings and try again. The Gradle task robotCommand --name="forward 60 cm" starts one (see Gradle tasks below).

Battery

Every opmode watches the battery: the line on the Driver Station, a battery graph, a warning at INIT below battery.low (12 V), and the lowest voltage of the opmode in the log. The battery is read a few times a second, as each reading is a request to the hub of its own.

The robot’s web pages

The Control Hub serves these pages itself, so they work whenever the robot is on, with an opmode running or not:

Page Does
http://192.168.43.1:8080/bear/config shows and edits the settings, live (see Settings)
/bear/config.properties the settings text: GET reads it, POST with text/plain replaces it
/bear/graphs live graphs, Driver Station lines, buttons for commands
/bear/graphs/data the same as JSON, for scripts
/bear/command?name=... POST starts a command
/bear/matchLogs downloads FIRST’s match logs as a zip, and deletes them from the robot

Over USB instead of WiFi, run adb forward tcp:8080 tcp:8080 and use http://localhost:8080.

Gradle tasks

BearPlatform’s Gradle plugin adds tasks for these pages to the robot’s module, TeamCode. They are plain Gradle, so they work the same on Windows, macOS and Linux. In Android Studio, they are in the Gradle tool window, under TeamCode › Tasks › robot: double-click one to run it. In a terminal, run ./gradlew :TeamCode:sendConfig (gradlew.bat on Windows).

Task Does
sendConfig sends res/raw/config.properties to the robot; --file=other.properties sends another file
robotCommand --name="forward 60 cm" starts a command; without a name, lists the ones offered now
downloadMatchLogs downloads the match logs into a new folder in TeamCode/matchLogs, and deletes them from the robot; --into=folder puts them elsewhere

To give a task options in Android Studio, right-click it in the Gradle tool window, choose Modify Run Configuration, and add them after the task’s name.

The tasks talk to the robot on its WiFi. Over USB, add bear.robot=usb to gradle.properties, or -Pbear.robot=usb to the command: they forward the robot’s port with the Android SDK’s adb first.

The Quickstart comes with the plugin. Another project adds it in two places: the top-level build.gradle,

plugins {
    id 'nl.beargineers.platform' version '0.2.0' apply false
}

and TeamCode/build.gradle, after the other apply plugin lines:

apply plugin: 'nl.beargineers.platform'