Skip to content

About

C++ package for bridging ROS2 over UDP, TCP, or a custom implemented network interface

Topics

Resources

Stars

52 stars

Watchers

2 watching

Forks

Repository files navigation

Network Bridge

CI

Network Bridge is a lightweight ROS2 node designed for robust communication between robotic systems over arbitrary network protocols. Supporting UDP, TCP, and ZMQ protocols out of the box, this packages seamlessly bridges ROS2 topics across networks, facilitating effective remote communications between a base station and robotic systems, or between multiple robotic systems.

Installation

Installation via apt

Install with:

sudo apt install ros-<distro>-network-bridge

Building from Source

Simply clone the repository into your ROS2 workspace and build with colcon build.

Usage

Demo

TCP

ros2 launch network_bridge tcp.launch.py

ros2 topic pub /tcp1/MyDefaultTopic std_msgs/msg/String "data: 'Hello World'"

ros2 topic echo /tcp2/MyDefaultTopic

UDP

ros2 launch network_bridge udp.launch.py

ros2 topic pub /udp1/MyDefaultTopic std_msgs/msg/String "data: 'Hello World'"

ros2 topic echo /udp2/MyDefaultTopic

ZMQ

ros2 launch network_bridge zmq.launch.py

ros2 topic pub /zmq1/test_topic std_msgs/msg/String "data: 'Hello World'"

ros2 topic echo /zmq2/test_topic

Talker/listener demos

The installed files in demo/ bridge sample chatter and static transforms. The server starts both TCP and UDP bridges. Run the server in one terminal:

ros2 launch network_bridge demo_server.launch.py

In another terminal, run either client:

ros2 launch network_bridge tcp_demo_client.launch.py
# Or:
ros2 launch network_bridge udp_demo_client.launch.py

The talkers publish automatically. The listeners print the messages received through the bridge. The demo_nodes_cpp runtime dependency is installed with this package, or resolved by rosdep when building from source.

For separate hosts, use the server's address on the TCP client:

ros2 launch network_bridge tcp_demo_client.launch.py server_host:=SERVER_IP

For UDP, configure both hosts. On the server:

ros2 launch network_bridge demo_server.launch.py udp_server_address:=0.0.0.0 udp_receiver_host:=CLIENT_IP

On the client:

ros2 launch network_bridge udp_demo_client.launch.py receiver_address:=0.0.0.0 server_host:=SERVER_IP

Replace SERVER_IP and CLIENT_IP with the hosts' reachable addresses. The port arguments are available through each launch file's --show-args option.

Configuration

Simply setup the network interface parameters and list your desired topics to get started. If you are using UDP over cellular data, it is recommended to setup a VPN to facilitate connection. Also, please note that no encryption occurs within this package. Currently, if you would like encryption, you must use a VPN.

See config/Udp1.yaml for a description of all parameters, as well as the TCP example configuration files.

Minimal Example

The following configuration examples demonstrate a robot sending a message on /gps/fix over UDP to a basestation that will then re-publish the message. This works seamlessly on all message types, so long as they are built and sourced on both ends of the transmission.

Robot

/udp_sender:
  ros__parameters:
    UdpInterface:
      local_address: "192.168.1.2"
      receive_port: 5001
      remote_address: "192.168.1.3"
      send_port: 5000

    topics:
      - "/gps/fix"

Base Station

/udp_receiver:
  ros__parameters:
    UdpInterface:
      local_address: "192.168.1.3"
      receive_port: 5000
      remote_address: "192.168.1.2"
      send_port: 5001

Special case: TF

The TF topic /tf or /tf_static are handled as a special cases. The subscriber side will listen to all TF messages, accumulate them (similarly to a TF buffer) and send all of them at the specified rate. The behavior can be disabled or forced using the is_tf configuration.

If some TFs need to be excluded or if the list of TFs to include is finite, one can use the include and exclude regex parameters. A transform is matched (hence excluded or included) if either the frame_id or child_frame_id are matching a pattern.

/udp_sender:
  ros__parameters:
    UdpInterface:
      local_address: "192.168.1.2"
      receive_port: 5001
      remote_address: "192.168.1.3"
      send_port: 5000

    topics:
      - "/prefix/tf"
      - "/tf_static"

    /prefix/tf:
      - is_tf: True
      - is_static_tf: False
      - rate: 10.

    /tf_static:
      - rate: 1.0
      - is_static_tf: True
      - exclude: ["standoff.*", "spacer.*", ".*wheel_link", ".*cliff.*"]

Choice of protocol

  • UDP: Use UDP for low-latency, high-throughput communications, where occasional data loss is tolerable. Ideal for real-time telemetry data like sensor streams.

  • TCP: Opt for TCP when data integrity and reliability are critical. This ensures that control commands and state transitions are reliably delivered, though with potentially higher latency.

  • ZMQ: Use ZMQ for one-to-many PUB/SUB delivery or PUSH/PULL load distribution. These interfaces are unidirectional: servers send and clients receive. Run a second pair for communication in the other direction.

The ZMQ plugin uses the system ZeroMQ library and cppzmq headers, installed by rosdep through libzmq3-dev. No ROS vendor package or source download is required.

ZMQ Communication Patterns

ZMQ supports multiple messaging patterns. This package currently supports two, configurable via the pattern parameter:

  • PUB/SUB (pattern: pub_sub): One publisher broadcasts messages to multiple subscribers. Best for one-to-many data distribution (e.g., sensor streams to multiple consumers). Subscribers receive only the topics they subscribe to; late-joining subscribers miss messages sent before connection.

  • PUSH/PULL (pattern: push_pull): One pusher sends messages to a pool of pullers in a round-robin fashion. Best for load-balanced pipelines where each message must be processed by exactly one consumer. The bridge sends without blocking its ROS executor. Samples are dropped when the send queue is unavailable, so this does not guarantee delivery of every ROS message.

Network protocols are implemented as pluginlib plugins, allowing the creation of arbitrary interfaces using the abstract class include/network_interfaces/network_interface_base.hpp. Any interface that can send and receive bytes could theoretically be implemented, including protocols that go beyond point-to-point communication. Please consider opening a pull request if you implement a new network interface.

Tuning

This node can be launched with logger level DEBUG, which provides useful information for tuning the compression, rate and stale message parameters. For each message that is sent, the receiving side will output the number of bytes received, the decompressed size in bytes and the transmission delay.

Contributing

Thank you for considering contributing!

Code Formatting

Python code is formatted with black, and C++ is formatted with uncrustify.

Pre-commit hooks

To ease the friction of linting, there are pre-commit hooks that you can install:

sudo apt install pre-commit

pre-commit run -a # Run on all files manually

pre-commit install # Run on commit automatically

which will reformat code automatically when you commit changes.

Acknowledgements

This package was developed for use in the Indy Autonomous Challenge by the Purdue AI Racing team. Inspiration was taken from mqtt_client (https://github.com/ika-rwth-aachen/mqtt_client/).

About

C++ package for bridging ROS2 over UDP, TCP, or a custom implemented network interface

Topics

Resources

Stars

52 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages