Skip to content

ROS2 web bridge

ROS / ros eco / packages

WebBridge is a bridge between ROS and the Web. - exposes ROS topics, services, and parameters over WebSockets using JSON messages. - A browser or any web app can connect via roslib.js (JavaScript client). - There are other client implementation except js like python roslibpy

install

sudo apt install ros-humble-ros-humble-rosbridge-suite

usage

launch
ros2 launch rosbridge_server rosbridge_websocket_launch.xml

minimal

  • Connect for javascript
  • Open Console from web developer tools for view log output
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8" />
    <script src="https://cdn.jsdelivr.net/npm/roslib@1/build/roslib.min.js"></script>
    <title>ROS Bridge Demo</title>
    
    <script>
      // Connecting to ROS
      // -----------------
      var ros = new ROSLIB.Ros();
      ros.connect('ws://localhost:9090');
        ros.on('connection', function() {
            console.log('Connected to websocket server.');
        });
        ros.on('error', function(error) {
            console.log('Error connecting to websocket server: ', error);
        });
        ros.on('close', function() {
            console.log('Connection to websocket server closed.');
        }); 
        // -----------------    
    </script>
    

Parameter

  • declare parameter
1
2
3
4
var param1 = new ROSLIB.Param({
        ros: ros,
        name: '/minimal:param1'
    });

parameter name

node_name:param_name

  • get / set
1
2
3
4
5
6
//get
param1.get(function(value) {
            displayParam1(value);
        });
//set
param1.set(newValue);
ros2 node
#!/usr/bin/env python3


import rclpy
from rclpy.node import Node
from rcl_interfaces.msg import SetParametersResult

PARAM1 = "param1"
PARAM2 = "param2"

class MyNode(Node):
    def __init__(self):
        node_name="minimal"
        super().__init__(node_name)
        p1 = self.declare_parameter(PARAM1, 1)
        p2 = self.declare_parameter(PARAM2, 2)
        self.get_logger().info(f"P1: {p1.value}")
        self.get_logger().info(f"P1: {p2.value}")
        self.add_on_set_parameters_callback(self.param_callback)


    def param_callback(self, params):
        for param in params:
            self.get_logger().info(f"Parameter '{param.name}' changed to: {param.value}")

        return SetParametersResult(successful=True)


def main(args=None):
    rclpy.init(args=args)
    node = MyNode()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()
HTML/Js
full demo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdn.jsdelivr.net/npm/roslib@1/build/roslib.min.js"></script>
<title>ROS Bridge Demo</title>

<script>
  // Connecting to ROS
  // -----------------
  var ros = new ROSLIB.Ros();
  ros.connect('ws://localhost:9090');
    ros.on('connection', function() {
        console.log('Connected to websocket server.');
    });
    ros.on('error', function(error) {
        console.log('Error connecting to websocket server: ', error);
    });
    ros.on('close', function() {
        console.log('Connection to websocket server closed.');
    }); 
    // -----------------    
</script>


<script>
    // Reading the parameter 'param1'
    var param1 = new ROSLIB.Param({
        ros: ros,
        name: '/minimal:param1'
    });

</script>

<body>
    <label for="param1Value">param1 value:</label>
    <span id="param1Value">Loading...</span>
    <button onclick="refreshParam1()">Refresh</button>
    <button onclick="updateParam1()">Update</button>

    <script>
        function displayParam1(value) {
            document.getElementById('param1Value').textContent = value;
        }

        // Initial fetch and display
        param1.get(function(value) {
            displayParam1(value);
        });

        // Refresh button handler
        function refreshParam1() {
            param1.get(function(value) {
                displayParam1(value);
            });
        }

        function updateParam1() {
            const newValue = prompt("Enter new value for param1:");
            if (newValue !== null) {
                param1.set(newValue);
                refreshParam1();
            }
        }


    </script>
</body>

Subscriber

Implement subscriber to ros topic The demo topic publish int counter The js subscribe using bridge

don't forget

ros2 launch rosbridge_server rosbridge_websocket_launch.xml
simple publisher
import rclpy
from rclpy.node import Node
from std_msgs.msg import Int32

class CounterPublisher(Node):
    def __init__(self):
        super().__init__('counter_publisher')
        self.publisher_ = self.create_publisher(Int32, 'counter', 10)
        self.counter = 0
        self.timer = self.create_timer(1.0, self.timer_callback)

    def timer_callback(self):
        msg = Int32()
        msg.data = self.counter
        self.publisher_.publish(msg)
        self.get_logger().info(f'Publishing: {self.counter}')
        self.counter += 1

def main(args=None):
    rclpy.init(args=args)
    node = CounterPublisher()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        rclpy.shutdown()

if __name__ == '__main__':
    main()
simple web bridge subscriber
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdn.jsdelivr.net/npm/roslib@1/build/roslib.min.js"></script>
<title>ROS2 Counter Subscriber</title>
<script>
  // Connect to ROS bridge
  var ros = new ROSLIB.Ros();
  ros.connect('ws://localhost:9090');
  ros.on('connection', function() {
    console.log('Connected to websocket server.');
  });
  ros.on('error', function(error) {
    console.log('Error connecting to websocket server: ', error);
  });
  ros.on('close', function() {
    console.log('Connection to websocket server closed.');
  });

  // Subscribe to the 'counter' topic
  var counterListener = new ROSLIB.Topic({
    ros: ros,
    name: '/counter',
    messageType: 'std_msgs/Int32'
  });

  counterListener.subscribe(function(message) {
    document.getElementById('counterValue').textContent = message.data;
  });
</script>
</head>
<body>
  <h2>ROS2 Counter Subscriber</h2>
  <label for="counterValue">Current counter value:</label>
  <span id="counterValue">Waiting for data...</span>
</body>
</html>

Service

don't forget

ros2 launch rosbridge_server rosbridge_websocket_launch.xml
simple service
#!/usr/bin/env python3


import rclpy
from rclpy.node import Node
from std_srvs.srv import Trigger
from rclpy.qos import qos_profile_services_default

TOPIC = "trigger_srv"

class MyNode(Node):
    def __init__(self):
        node_name="minimal_srv"
        super().__init__(node_name)
        self.srv = self.create_service(Trigger, TOPIC, self.handler, qos_profile=qos_profile_services_default)
        self.get_logger().info("Hello ROS2")

    def handler(self, request: Trigger.Request, response: Trigger.Response):
        self.get_logger().info("Trigger service called")
        response.success = True
        response.message = "success"
        print(response)
        return response

def main(args=None):
    rclpy.init(args=args)
    node = MyNode()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()
simple web bridge subscriber
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdn.jsdelivr.net/npm/roslib@1/build/roslib.min.js"></script>
<title>ROS2 Trigger Service Client</title>
<script>
  // Connect to ROS bridge
  var ros = new ROSLIB.Ros();
  ros.connect('ws://localhost:9090');
  ros.on('connection', function() {
    console.log('Connected to websocket server.');
  });
  ros.on('error', function(error) {
    console.log('Error connecting to websocket server: ', error);
  });
  ros.on('close', function() {
    console.log('Connection to websocket server closed.');
  });

  // Create the service client
  var triggerClient = new ROSLIB.Service({
    ros: ros,
    name: '/trigger_srv',
    serviceType: 'std_srvs/Trigger'
  });

  function callTriggerService() {
    var request = new ROSLIB.ServiceRequest({});
    triggerClient.callService(request, function(result) {
      document.getElementById('serviceResult').textContent =
        'Success: ' + result.success + ', Message: ' + result.message;
    }, function(error) {
      document.getElementById('serviceResult').textContent =
        'Service call failed: ' + error;
    });
  }
</script>
</head>
<body>
  <h2>ROS2 Trigger Service Client</h2>
  <button onclick="callTriggerService()">Call Trigger Service</button>
  <div id="serviceResult">Result will appear here.</div>
</body>
</html>