nbtool - northern-bites/nbites GitHub Wiki

NOW SEE tool8

nbtool is the Northern Bites' new java tool. It is designed to aid debugging and productivity.

To run the tool: cd in nbites/src/nbtool and enter the command:

    ./RUNnbtool

To run nbcross: while the tool is running, cd into nbites/src/nbcross and run the command:

 make nbcross

If everything works correctly, the 'cpp' label in the sidebar on the right of the tool should turn green!


This document also covers the logging and control frameworks that integrate with nbtool

first version :

https://github.com/philipkoch/nbites/commit/5e5a9888068769b1a25b05d669327d01b445c83b

latest version:

https://github.com/philipkoch/nbites/tree/tool6-clean

The first few sections of this document cover a few functional topics. More detailed pages for specific sections of the logging system are listed after.

overview

The new logging and tool system has three components. First, there is the c++ code that runs on the robot – logging and control . These two components coordinate getting information out of man during play, as well as allowing external applications to manipulate the man process. Next, there is the external java tool (nbtool). This cross-platform tool facilitates offline manipulation of logged data, offline communication with nbcross instances, and communication with active robots. The final section is nbcross, which allows nbtool to call and examine the output of c++ code, usually portions of man being run offline.

how to run nbtool

The simplest and quickest part of the new system to use is nbtool. To run the tool, you must have at least java SE 1.7 (i.e. version 7) installed on your machine. To get your java version, execute

java -version

Install java on ubuntu here: https://www.digitalocean.com/community/tutorials/how-to-install-java-on-ubuntu-with-apt-get

With 1.7 or better, you can copy the entire nbites directory from any team member who has built the tool. Then execute RUNnbtool-nobuild (with a correctly set NBITES_DIR variable – see below).

To compile the tool, you must have a java SDK (Standard Development Kit) version 1.7 or higher. To check your sdk version, execute

javac -version

The tool requires google's protobuf library to compile, but a copy of this library's source is included. Compiling the tool with BUILDnbtool requires that the environment variable NBITES_DIR be set correctly. If you are running a linux machine and have used the setup script, this should be set automatically. Otherwise, you will need to set this variable manually. In any case, execute env to check.

BUILD ERRORS RESEMBLING THE FOLLOWING ARE PROBABLY DUE TO BAD NBITES_DIR VARIABLES

mkdir: /build/nbtool: Permission denied

javac: directory not found: /build/nbtool

Usage: javac <options> <source files> use -help for a list of possible options

Another great option for building and editing the tool's src is to use an IDE like eclipse. You can link all of the tool source into your IDE's project even if that project is not in the nbites directory, which allows your edits to occur on the original source code without adding project configuration files and testing code to your nbites clone and git commits.

data formats

The tool's log format (indicated by file extension .nblog) is mirrored between the java and c++ implementations. The format has two major components and two minor components. In order:

1 description length, 4 bytes network order comprising a 32 bit signed integer.

2 description description length byte sized characters (UTF8) composing a human readable S expression. In the source, S expressions are called SExprs. Note also that if this string is null-terminated (which is not guaranteed), the null byte will be included in description length. This field is typically accessible in a given language by calling .tree() on the log. This will return the top-level SExpr object represented by the log's description. The source character array of the description is either inaccessible or nonexistent after the log has been read into the language.

3 data length, 4 bytes network order comprising a 32 bit signed integer.

4 data data length bytes of data, with any format allowed. Typically accessible in a given language by calling .data() on the log.

Therefore, the minimum size of any nblog is 8 bytes. For logs intended to be loaded by nbtool, the description field must start with the character string (nblog or the log will be rejected.

The 4 byte fields are required to be in network order. IO operations in java do not typically need to worry about this: IO operations in c++ almost always do. This is because java uses network order by default while c++ uses the host endianness, which on x86 machines is typically little-endian (the opposite of network order) In either case, worry about writing or reading logs can almost always be differed to nblog::Log::write() and nblog::Log::send() in c++ or nbtool.io.CommonIO.readLog() and nbtool.io.CommonIO.writeLog() in java.

####using log data The log format does not explicitly determine what format a log's data bytes will be in. Typically, some portion of the description will declare what information is stored in the data field. For example, YUVImage logs have a (type YUVImage) key value pair in their description which directs the tool to interpret the data bytes as pixels.

  • Even if the format of the data has been determined, further processing may be necessary. For example, the data fields of logs containing protobufs hold the serialized protobuf. To access fields of the protobuf, users must first deserialize the protobuf into a language appropriate object.

  • Except for default views (which don't try to parse a log), if the tool does not recognize a log's type it won't try to load views for it. So you may create logs of any format; as long as they declare a previously unused type the tool will not mistakenly try to parse them.

NOTE: the tool assumes it may load certain protobuf views for all logs whose type has prefix '-proto'

####using S expressions (SExpr in the source) Dedicated to Cheddar whose SExpr induced loss of sanity motivated the creation of these pages.

Though SExprs may at first be intimidating, they are a simple protocol for encoding nested lists (i.e., trees). Though Lisp uses SExprs as both source code and data, we allow and interpret a subset of the full S expression notation.

every SExpr node is either

  • an atom – i.e. an indivisible string
  • a list – i.e. a (possibly empty) list of other SExpr nodes.

Because the characters " ( ) are considered special in SExpr notation, atoms which would like to include these characters must escape them by surrounding the atom in " characters, which will not be included in the atom's value. To include an actual " character, use "" inside an escaped string.

Though all atoms are essentially strings, we may interpret these strings as integers, floats, or boolean values as necessary. Support for doing this in both languages is provided (see the valueAsX methods in the c++ impl and java impl ).

Here is an example YUVImage log's SExpr tree (note that in actual logs the SExpr is serialized into a more compact but equivalent string). This tree demonstrates how the first atom of a list can be used as the key with which to interpret the subsequent nodes – so SExprs can encode dictionaries.

( nblog

(created LogModule "01.05.2015 23:34:45")

(version 6)

(checksum 71290316)

( contents

(

 (type YUVImage)
 (from camera_TOP)
 (when 457970000)
 (iindex 2659)
 (nbytes 614400)
 (width 640)
 (height 480)
 (encoding "[Y8(U8/V8)]")

)

)

(host_type V4ROBOT)

)

This SExpr demonstrates a few standard (and in some cases necessary) paths in a log's tree. All logs must have their top level node be a list – the tree cannot start with an atom, and the tool ignores any nodes after the top-level list terminates. Second, all logs which might need to be written to a filesystem (so not logs like command logs) must have as the first child node of the top-level-list the atom "nblog". These two requirements lead to the first characters in almost all logs serialized descriptions being

(nblog

In the top namespace of a log, a few keys (lists where the first node is an atom) are reserved. Here they are listed, and their typical values explained.

  • created "where" "when"
  • version "versionAsInt"
  • checksum signed 32 bit checksum of data.
  • contents one or more lists, where each list contains key-value pairs describing specific attributes of a certain data-type stored in this log (e.g., (type typeName) ). These 'sub-dictionaries' should be listed in the same order as their corresponding data is stored in the data field. For an example of this, see 'tripoint' logs.
  • host_type V4ROBOT, V5ROBOT, or UNKNOWN
  • from_address address from which this log was streamed, if applicable

adding views

In nbtool, views are ways of interpreting and displaying data to the user. The tool automatically loads the correct views when a log of a specific type is selected.

Each logview is a specific way of viewing a log of a certain type.

Every view must extend nbtool.gui.logviews.misc.ViewParent, which is an abstract class extending JPanel. ViewParent has one abstract method which subclasses must implement:

  • setLog(Log newlog) this method is called with the log to display as argument. Though any subclass may use the no-argument constructor to initialize GUI elements, populating those elements will likely need to wait until the relevant log is supplied by the GUI via this method.
  • views may modify the logs they are provided – the modifications will persist through the lifetime of the process but will not be written to fs unless the log is (re)saved.
  • views may conduct essentially any computation they want in this method, including requesting c++ computation via nbcross

ViewParent also has a few other methods which subclasses may override for non-standard functionalities. These methods have default implementations which effectively do nothing.

  • shouldLoadInParallel() returns a boolean letting the GUI know if this class's instances should be created and given their log in a separate (non-GUI) thread. By default, views are created and set in the GUI thread. Since Swing is single-threaded, the GUI cannot process other actions (such as user clicks) while views load. Returning true allows a view to take its time loading without freezing the entire tool – when setLog() returns, the GUI will synchronize with the view's thread and add it to the display.

  • alsoSelected(ArrayList<Log> also) provides the view with all other logs currently selected by the user, excluding the primary log supplied by setLog(). Though the order of these logs is undefined, in practice it is reasonably predictable.

View instances are automatically resized by the log display according to user actions. Subclasses only need to define what to paint/display in that space.


To get the tool to automatically load a view when logs are selected, two things must happen. First, the view's class must be added to the appropriate array in NBConstants.java's setupPossible() initialization function. The string key to which each array of classes is mapped expresses what log types the view is capable of displaying. So if you wish to load an instance of NewView.class whenever a log of type "NewType" is selected, add a line like

map.put("NewType", new Class[]{NewView.class});

to setupPossible().

There are two special super types: default and protobuf. Classes added to either of these keys must be capable of displaying all logs and all protobuf logs, respectively. The tool assumes classes mapped to default (DEFAULT_S in NBConstants.java) may be loaded for any log. It assumes classes mapped to protobuf (PROTOBUF_S in NBConstants.java) may be loaded for any protobuf log – which to the tool is any log whose type has prefix 'proto-'.

The second necessary step in getting a view to display is making sure it is enabled in a users view mapping. This is as simple as opening the LogToViewUtility in the utility pane of the tool and selecting the view under the appropriate type.

nblog and robot-side code

All logging and control code on the robot can be (and is) turned off by disabling the USE_LOGGING flag. If USE_LOGGING is enabled, four threads are created: log_main, which for now only handles reporting about the status of the robot, log_streamio, which handles sending any and all logs to connected tools, log_fileio – writing logs to the robot's filesystem, and control which is explained elsewhere. Note that these threads typically spend 99% of their time sleeping.

man/log contains the code specific to setting up the log server. See nblog for more details about logging on the robots.

man/control contains the code specific to setting up the control server. This server is responsible for communicating with hosts (like nbtool) outside the man process. control.h also includes a number of flags which control logging on the robot and can be remotely set by nbtool. See control for more details.

SPECIFIC COMPONENT PAGES


fin.

⚠️ **GitHub.com Fallback** ⚠️