Skip to main content

UDP Forwarder and ROS2 Publisher

udp_forwarder_node.cpp

This is the main file running the communications logic on Jonny Boi's side. It doublesis a ROS2 node that simultaneously acts as both a UDP server and a ROS2 publisher/subscriber,subscriber. receivingIts primary responsibilities are:

  • Receiving raw encoded protobuffersPBEnvelope packets over UDP from eitherthe Basestation or hardware microcontrollers
  • Deserializing the microcontrollersprotobuf or Basestationpayload and routingconverting themit tointo a custom ROS2 message
  • Publishing that ROS2 message over the appropriate destination.topic for internal nodes to consume
  • In the outbound direction, subscribing to ROS2 topics and converting messages back into protobufs to be sent as UDP packets

The Handler Pattern

The coremost ofimportant architectural concept in this file is athe registry-based handler dispatch system.system. WhenRather than having a PBEnvelopelarge arrivesswitch overstatement UDP,that handles every possible message type, the node extractsmaintains an unordered_map that maps each PBEnvelope::PayloadCase enum value to a dedicated handler object.

When a UDP packet arrives, the node parses it as a PBEnvelope and calls payload_case() ,to anidentify enum value that identifies what type ofthe message istype. inside,It andthen looks up the corresponding handler in anthe map and calls unordered_maphandle(envelope). on it. Each handler is a class that extends the abstract Handler base class and is solely responsible for deserializing one specific protobuf message type — deserializing the protobuf, mapping its fields to a ROS2 message, and publishing it as a ROS2 message on the appropriatecorrect topic.

Registering a new handler looks like this:

handlers_.emplace(
    static_cast<int>(PBEnvelope::kImuInfo),
    std::make_unique<ImuHandler>(this, "imu_data", 10)
);

The three constructor arguments are the payloadnode casepointer enum value,(so the handler instance,can andcreate a publisher), the ROS2 topic name withto publish on, and the publisher queue size. Adding support for a new message type is as simple as writing a new handler class and adding one emplace call here — the rest of the dispatch logic requires no changes. See the Adding a New Message Type page for a step-by-step guide.

The rx_loop Background Thread

UDP receiving runsdoes not happen on the ROS2 spin thread. Instead, the node spawns a dedicated background thread separatethat fromruns rx_loop() continuously, blocking on recvfrom() until a datagram arrives. This design ensures that the ROS2 executor is never blocked waiting for network I/O, and that incoming packets are processed as fast as the network delivers them regardless of what the ROS2 stack is doing.

This is worth keeping in mind when debugging. If you see unexpected behavior related to timing or message ordering, the source may be a race condition between the rx_loop thread and the ROS2 spin thread. ThisThe meansrunning_ flag is declared as std::atomic<bool> specifically to ensure safe cross-thread signaling during shutdown.

UDP Forwarding Behavior

Before dispatching to a handler, the node canforwards continuouslyevery receiveraw packetsUDP withoutdatagram blockingto both dstA_ and dstB_ unconditionally. This means every message type, regardless of its intended destination, is forwarded to both addresses. This is a known architectural limitation — see the ROS2Known executor.Limitations Keeppage thisfor inmore mindcontext whenand debuggingthe timingrationale orbehind threading issues.it.

Configuration Parameters

The node's network configuration is fully driven by ROS2 parameters declared at startup:

Parameter

Default

Description

listen_port,

5000

UDP port the node listens on

dst_a_port,

6000

First forwarding destination port

dst_b_port,

6001

Second andforwarding destination port

dst_ip

127.0.0.1

Destination IP for both forwarding targets

 are all declared as ROS2 parameters at startup andThese can be overridden at launch time without recompiling, via a ROS2 launch file or --ros-args.

flags without recompiling, making it easy to reconfigure the node for different network environments such as the Jetson on the rover versus a local development machine.UDP Forwarding

Currently, every received UDP packet is forwarded raw to both dstA_ and dstB_ before handler dispatch.

This implementation will CHANGE SOON. to forward ONLY to appropriate destinations.