Skip to content

MoosTranslation

Toby Schneider edited this page May 26, 2016 · 7 revisions

Preliminary docs on pAcommsHandler / pTranslator translation functionality

Since it's going to take me a bit to get the final Goby2 doc finished, I'm going to give you a preliminary start here how to use the moos<-->protobuf functionality built into the Goby2 moos applications. pTranslator and pAcommsHandler share the same code, so this applies to both. pTranslator can be thought of as a very minimal pAcommsHandler that simply immediately publishes all created messages. Note that pAcommsHandler requires DCCL extended protobuf messages, whereas pTranslator is fine working with vanilla protobuf messages.

Motivation: I needed a reasonably clean way to handle parsing the arbitrary (untyped) MOOS world to Google Protocol Buffers messages (protobuf) and the reverse (serialization). This replaces the <trigger>, <publish> and <layout> ... <moos_var> tags from Goby1. If you want to see what the autogenerated translator entries from Goby1 XML files are, you can run "dccl_xml_to_dccl_proto some_file.xml" and the relevant translator entries are written to stdout (along with writing the generated .proto to the current directory).

Schematically:

MOOS_VARs
   |
   v
pAcommsHandler1
   | (translator: "trigger" & "create")
   v
DCCL Protobuf Message
   | (DCCL encode, enqueue, send over water)
   | (receive over water, dequeue, DCCL decode)
   v
pAcommsHandler2
   |
   v
DCCL Protobuf Message
   | (translator: "publish")
   v
MOOS_VARs



MOOS_VARs
   |
   v
pTranslator
   | (translator: "trigger" & "create")
   v
Protobuf Message
   | (immediate loopback internally)
   v
pTranslator
   | (translator: "publish")
   v
MOOS_VARs

Steps to use pTranslator/pAcommsHandler:

  1. It's probably helpful to be looking at the output of "pTranslator -e" (example_config) which gives all the configurable options.

  2. The protobuf message must be loaded. Preferably (because of static / compile-time checking) use load_shared_library, e.g. load_shared_library: "/home/toby/lamss/lib/liblamss_protobuf.so" where liblamss_protobuf.so has some proto messages compiled in C++. Alternatively use load_proto-file: load_proto_file: "/home/toby/lamss/src/lib/liblamss_protobuf/node_report.proto"

    This compiles the proto file at runtime, so any syntax errors in the .proto file are not caught until then.

  3. Define a translator_entry for each protobuf "message" you want to use.

    Each translator_entry has three parts:

    1. exactly 1 trigger directive: defines when this message is to be created (either synchronously on a configurable period or asynchronously on every publish to a given variable)

      These two examples should pretty self-explanatory: :

      trigger {
        type: TRIGGER_TIME
        period: 5  # seconds
      

      }

      trigger { # (optional)
      type: TRIGGER_PUBLISH moos_var: "NODE_REPORT_LOCAL_PB"

      }

    2. 1 or more create directive(s): defines how to assemble the protobuf message. You can use multiple creates, which are all merged to create the final (single) protobuf message. For both create and publish you currently have 5 parse/serialize techniques:

      1. TECHNIQUE_PROTOBUF_TEXT_FORMAT: exactly the same as if you used the Google TextFormat class: https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.text_format.

      2. TECHNIQUE_PROTOBUF_NATIVE_ENCODED: exactly the same as if you used the default binary Google encoding (binary), represented as a byte string. This tends to break the MOOS tools that assume strings are ASCII / UTF-8. I'm not even sure MOOS can handle transporting this correctly.

      3. TECHNIQUE_COMMA_SEPARATED_KEY_EQUALS_VALUE_PAIRS: all fields represented as key1=value1,key2=value2,... Messages with submessages flattened and the keys assembled by concatenation separated with "_". This is similar to the existing "NODE_REPORT" variable.

      4. TECHNIQUE_FORMAT: sort of like printf / scanf, except instead of typed directives (e.g. %d), I use numeric directives that correspond the protobuf message field id (e.g. foobar=%2%). Submessages can be referenced using ":" (e.g. %5:1%, where field 5 is a Message), repeated fields can be referenced using "." (e.g. %7.1%, where field 7 is repeated). Note the ending % on each directive, which is different than printf.

      5. TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT (my recommendation for MOOS). Same as TECHNIQUE_PROTOBUF_TEXT_FORMAT but prefixed with "@PB[TypeName] ", so that you can put multiple Protobuf Types in a single MOOS Variable (if you really need to). It's also quite human readable and allows for programs to read / write generic Protobuf messages.

        This technique is useful enough, I made two shortcut functions for use in your C++ code (#include "goby/moos/moos_protobuf_helpers.h"): :

        // writes `msg` to `out` using TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT
        void serialize_for_moos(std::string* out, const google::protobuf::Message& msg)
        // writes `in` to `msg` using TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT
        void parse_for_moos(const std::string& in, google::protobuf::Message* msg)
        
    3. 1 or more publish directive(s): defines how to disassemble the protobuf messages. Same as create but the other way around. Note that on publish, the final value is attempted to be cast to double. If this succeeds a MOOS double type is published, else a MOOS string type is published.

A translator_entry needs to be defined for each protobuf message you want to use. Multiple translator_entries can be created for a given Protobuf Message if they are all TRIGGER_PUBLISH.

All this verbiage is useless without an example. See test.moos which uses node_report.proto (change library paths and then "pAntler test.moos").

  • pTranslator_MOOS2PB converts a bunch of NAV* MOOS junk into a single TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT encoded message and writes it to NODE_REPORT_LOCAL_PB. - pTranslator_PB2MOOS does the opposite, taking the nice NODE_REPORT_LOCAL_PB and writing VEHNAME_NAV_X and VEHNAME_NAV_Y (shows use of TECHNIQUE_FORMAT and how it works in moos_var too).