---
# System prepended metadata

title: 'Day 2: Communications (Whiteboard)'

---

# Day 2: Communications (Whiteboard)

## Understanding Nested Publish/Subscribe

Three-layer:
- interthread: within a process
- interprocess: within a vehicle (ZeroMQ)
- intervehicle: within a squadron or cluster of vehicles

### Interprocess

- A single publisher
- A single subscriber


```mermaid
graph TB
  publisher-->subscriber
```

In Goby3 interprocess:
```mermaid
graph TB
  publisher-->gobyd-->subscriber
```

```mermaid
graph TB
  publisher1-->subscriber1a & subscriber1b
  publisher2-->subscriber2
```

less frequently:
```mermaid
graph TB
  publisher1a & publisher1b  -->  subscriber1a & subscriber1b
```

All of these topologies are supported in Goby.

## Hands-on with one publisher / one subscriber in Goby3

### Interprocess

Copied the single thread pattern into two new binaries: goby3_course_interprocess_publisher/subscriber


#### Qualifying a publication in Goby

To publish in Goby:

- *layer*: interprocess
- *group*: similar to LCM *channel*, ROS *topic* or MOOS *variable*
- marshalling *scheme*: (Protobuf)
- data *type*. (Protobuf == Message ==> C++ Class : public google::protobuf::Message)

We still to decide on only two things now:

- *group*
- *type* (or Message)

GPSPosition -> `groups::gps1` and `groups::gps2`.
GPSDiagnostics -> `groups::gps1` and `groups::gps2`.

Publications on a particular layer are automatically published to all inner layers.

#### Anatomy of a goby::middleware::Group

Group
- thought of as a "union" of a string/integer (uint8_t).
- high bandwidth layers (interthread / interprocess): string + integer is used: "goby3_course::usv_nav;1"
- low bandwidth (intervehicle): integer is used.

Some examples:

```cpp
using goby::middleware::Group;

// valid for interprocess and interthread
constexpr Group foo1{"foo"};

// valid for all three of the layers: "foo;2", 2
constexpr Group foo2{"foo", 2};

// valid for all three layers: "3", 3
constexpr Group bar{3};

// bar == bar2 on intervehicle but not on interprocess/interthread
constexpr Group bar2{"bar", 3};

// 0 == "broadcast_group" ~= "no group"
constexpr Group bar_groupless{"bar", Group::broadcast_group};
```

Let's say we want send the vehicle's health.

Created a group `health_status`.

### Create a Protobuf message

Create a HealthStatus message.

### Add messages to Publisher code

Send our health status at 1 Hz.

### Add subscriber

Lambdas expressions.


```mermaid
graph TB
  goby3_course_interprocess1_publisher  -->|HealthStatus| goby3_course_interprocess1_subscriber
```

### Interthread

Convert the interprocess pair of applications into a single standalone process (application) with two threads.

MultiThreadApplication
- thread type is goby::middleware::Thread -> goby::middleware::SimpleThread (3-layer).
    -`loop()` method
    - `interthread()`, `interprocess()`, and `intervehicle()`
    - configuration may differ from the parent application

```mermaid
graph TB
  subgraph goby3_course_interthread1
    Publisher -->|HealthStatus| Subscriber
  end
```

### Cross layer: Interthread & Interprocess

```mermaid
graph TB
  subgraph goby3_course_interthread1
    Publisher --> Subscriber
  end

  Publisher-->goby3_course_interprocess1_subscriber
```
### Intervehicle

"Slow links": <= 1 Mbps, often much much less: acoustic modems, satcomms, etc.

```mermaid
graph TB
    subgraph intervehicle / Goby Acomms
    buffer[Dynamic Buffer]
    dccl[DCCL]
    amac1[AMAC, link 1]
    driver1[Modem Driver, link1]
    amac2[AMAC, link N]
    driver2[Modem Driver, link N]
    dccl-->buffer
    buffer-->driver1
    driver1-->buffer
    amac1-->driver1
    buffer-->driver2
    driver2-->buffer
    amac2-->driver2
    end
```

### DCCL

libdccl.org

DCCL1 == XML definition
DCCL2+ == Protobuf definition

(DCCL3 is current version).

Protobuf (vanilla):
```protobuf
syntax="proto2";
message NavigationReport {
  required double x = 1;
  required double y = 2;
  required double z = 3;
  enum VehicleClass { AUV = 1; USV = 2; SHIP = 3; }
  optional VehicleClass veh_class = 4;
  optional bool battery_ok = 5;
}
```

DCCL:
```protobuf
syntax="proto2";
import "dccl/option_extensions.proto";

message NavigationReport {
  option (dccl.msg) = { codec_version: 3 
  id: 124
  max_bytes: 32
  }

  required double x = 1 [(dccl.field) = { min: -10000 max: 10000 precision: 1 }];
  required double y = 2 [(dccl.field) = { min: -10000 max: 10000 precision: 1 }];
  required double z = 3 [(dccl.field) = { min: -5000 max: 0 precision: 0 }];
  enum VehicleClass { AUV = 1; USV = 2; SHIP = 3; }
  optional VehicleClass veh_class = 4;
  optional bool battery_ok = 5;
}
```

#### Setting up gobyd's InterVehiclePortal

Created some configuration directories.

Pick a driver: UDPMulticastDriver: UDP multicast 

#### Subscription forwarding
(Note text aligns with arrows beneath)
```mermaid
sequenceDiagram
    publisher->>publisher: data1
    publisher->>publisher: data2
    subscriber->>publisher: subscription message
    publisher->>subscriber: data3
    publisher->>subscriber: data4
```



```mermaid
graph TB
  subgraph veh1
    goby3_course_intervehicle1_publisher
  end
  subgraph veh2
    goby3_course_intervehicle1_subscriber
  end

  goby3_course_intervehicle1_publisher-->goby3_course_intervehicle1_subscriber
```

#### Dynamic Buffer

Goby3 buffer is a priority queue:
- base priority value
- time sensitive priority (ttl)

Assume we have three messages type (1,2,3):

- 1: base value 1 and ttl: 1000 seconds ("vehicle status")
- 2: base value 2 and ttl: 2000 seconds ("sensor data")
- 3: base value 1 and ttl: 3000 seconds ("debug engineering data" or "health status IF good or nominal")

![](https://i.imgur.com/BNouiJi.png)

```protobuf
message DynamicBufferConfig
{   
  optional bool ack_required = 2 [default = false];
    // lowest value takes precedence
    optional double blackout_time = 3 [
        default = 0,
        (dccl.field) =
            {min: 0 max: 3600 precision: 0 units {base_dimensions: "T"}}
    ];
    // larger value takes precedence
    optional uint32 max_queue = 4
        [default = 1000, (dccl.field) = {min: 1 max: 1000}];
    // true takes precedence over false
    optional bool newest_first = 5 [default = true];
    // use average of values
    optional double ttl = 6 [
        default = 1800,
        (dccl.field) =
            {min: 1 max: 86400 precision: 0 units {base_dimensions: "T"}}
    ];
    // use average of values
    optional double value_base = 7
        [default = 100, (dccl.field) = {min: 1 max: 1000 precision: 0}];
}
```

#### Modem Drivers

There are 8 drivers in the open source project (Goby3):

- WHOI Micro-Modem (v1, v2)
- Iridium 9523 and similar (RUDICS/SBD)
- Iridium RUDICS and DirectIP shore-side connections
- Benthos ATM900 Modems
- delResearch Popoto Modem
- UDP Point-to-point
- UDP Multicast (using now)
- ABC Driver (demo for writing new drivers)

https://github.com/GobySoft/goby3/pulls

(If contributing your own driver) Please don't worry if it's not "finished".

## Returning to the Trail example

N AUVs trailing 1 USV communicates to a topside (ship, shore station).

```mermaid
graph TD
    auv0-->|"auv_nav;2"|usv
    auv1-->|"auv_nav;2"|usv
    auvN-->|"auv_nav;2"|usv
    usv-->|"usv_nav;1"|auv0
    usv-->|"usv_nav;1"|auv1
    usv-->|"usv_nav;1"|auvN

    usv==>|"usv_nav;1"|topside
    usv==>|"auv_nav;2"|topside
```

Groups: `auv_nav;2`, `usv_nav;1`.

Message type: `Navigation Report`



1. goby3_course_auv_manager
1. goby3_course_usv_manager
1. goby3_course_topside_manager


```mermaid
graph TD
    subgraph auvN
        auvm[goby3_course_auv_manager]
    end
    subgraph usv
        usvm[goby3_course_usv_manager]
    end
    subgraph topside
        topsidem[goby3_course_topside_manager]
    end

    auvm-->|"auv_nav;2"|usvm-->|"usv_nav;1"|topsidem
    usvm-->|"auv_nav;2"|topsidem
    usvm-->|"usv_nav;1"|auvm
```

---
```






```