Skip to content
Marco A. Gutiérrez edited this page Jul 20, 2022 · 19 revisions

The Acoustics Subsystem

The Acoustics Subsystem was designed to be very flexible. It consists of a data-bus on which all messages are publicly forwarded, a CommsModel which provides the environmental model that determines how a packet should be forwarded and whether or not the packet should be dropped or garbled. By default the Comms subsystem comes with a SimpleAcousticModel which only delays the transmission of the message based on the position of the transmitter and receiver in water. The comms model however is flexible enough so that we can apply the appropriate delays.

Overall Architecture

In the above diagram you can see an example of how a message is transmitted between two vehicles. On the external interface we have a lrauv_ignition_plugins::msgs::LRAUVAcousticMessage protobuf (blue arrow) being sent by an application on the vehicle with address 2. The AcousticCommsPlugin will timestamp and add the vehicles position onto the message and broadcast it on the topic /comms/internal/ using a lrauv_ignition_plugins::msgs::LRAUVInternalMessage. The AcousticCommsPlugin will listen and forward the packet as quickly as it can to the corresponding Communications Model plugin. The communications models will then decide whether and when to forward the packet to the receiver.

How to Send and Receive Data Packets on the Acoustic Subsystem.

In this tutorial we will be exploring how to send and receive data packets. There are two ways of doing this. The first is using the lrauv_ignition_plugins/comms/CommsClient.hh header and the second is directly calling the relevant ignition topics (reading the linked header should also give you a rough idea of how to write your own client).

Using CommsClient

CommsClient is an extremely easy to use method for handling sending of messages, however it needs C++11 or above to be used. The usage is as follows:

#include <lrauv_ignition_plugins/comms/CommsClient.hh>

using namespace tethys;
using AcousticMsg = lrauv_ignition_plugins::msgs::LRAUVAcousticMessage;

// Bind client to address 1
CommsClient client(1, [](const auto msg){
   // Your callback function
   // To get the data call
   msg.data();
   // To get who the message is from
   msg.from();
});

// For sending data

AcousticMsg msg;
// Who to send to
msg.set_to(2);
// From who
msg.set_from(1);
// `LRAUVAcousticMessage_MessageType_Other` means its a data packet
msg.set_type(AcousticMsg::MessageType::LRAUVAcousticMessage_MessageType_Other);
// The data
msg.set_data("test_message");
client1.SendPacket(msg);

An example may be found in the tests here.

Direct method

For this method you will need to understand how ignition-transport works. It is recommended to read this tutorial first.

To get started instantiate a world using ignition:

ign gazebo -v4 acoustic_comms_test.sdf

Two boxes will be spawned. Each of these boxes has an instance of the comms plugin and the range bearing plugin. The boxes publish what they receive on the /comms/external/{address}/rx topic. The comms client will also forward data published from the /comms/external/{address}/txtopic to the relevant client. In a new terminal enter:

ign topic --list

You should see two sets of RX and TX topics. Here is a minimal echo program:

  #include <ignition/transport/Node.hh>
  #include "lrauv_acoustic_message.pb.h"

  int address = 1;
  ignition::transport::Node node;
  ignition::transport::Node::Publisher transmitter;
  
  //////////////////////////////////////////////////
  /// \brief Function called each time a message is recieved by the comms subsystem.
  void cb(const lrauv_ignition_plugins::msgs::LRAUVAcousticMessage &_msg)
  {
    std::cout << msg.from() << ": " << msg.data();

    lrauv_ignition_plugins::msgs::LRAUVAcousticMessage returnMsg;
    // Who to send to
    msg.set_to(msg.from());
    // From who  
    msg.set_from(address);

    // `LRAUVAcousticMessage_MessageType_Other` means its a data packet
    msg.set_type(AcousticMsg::MessageType::LRAUVAcousticMessage_MessageType_Other);

    // The data
    msg.set_data(msg.data);

    // Send the data
    transmitter.Publish(msg);
  }

  int main(int argc, char** argv)
  {
    transmitter = node.Advertise<lrauv_ignition_plugins::msgs::LRAUVAcousticMessage>(
      "/comms/external/" + std::to_string(address) + "/tx");

    node.Subscribe(
      "/comms/external/" + std::to_string(address) + "/rx",
      cb
    );

    while(true) { sleep(1); }
  }