ROS Web Tutorial Part 1- rosbridge server and roslibjs

ROS web tutorial part 1 - rosbridge server and roslibjs- Note: Tutorial adapted for ROS2 Humble

Set up Rosbridge Server

  • Create workspace
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
  • Create a package called robot_gui_bridge that depends on rosbridge_server
ros2 pkg create robot_gui_bridge --dependencies rosbridge_server
  • Install all required dependencies from the root of the workspace
cd ..
sudo apt update
rosdep install --from-paths src --ignore-src -r -y
  • Alternatively, you can install the package manually using sudo apt install ros-humble-rosbridge-suite
    • However, using rosdep is a better practice, especially when collaborating with others
  • Make a launch file for the package
mkdir src/robot_gui_bridge/launch && cd src/robot_gui_bridge/launch
touch websocket.launch.py
  • Modify CMakeLists.txt to install launch file
# CD into ros2_ws
cd ../../..
# Copy and paste into CMakeLists.txt
install(
  DIRECTORY launch/
  DESTINATION share/${PROJECT_NAME}/
)
  • Build the workspace
colcon build --packages-select robot_gui_bridge
  • Source the workspace to make the package available for use
source install/setup.bash
  • Launch the websocket server using the launch file
ros2 launch robot_gui_bridge websocket_launch.py
[INFO] [launch]: All log files can be found below /home/chxtio/.ros/log/2024-09-24-07-01-23-452406-172.20225150-1507
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [rosbridge_websocket-1]: process started with pid [1509]
[rosbridge_websocket-1] [INFO] [1727186484.038599832] [rosbridge_websocket]: Rosbridge WebSocket server started on port 9090

Set up roslibjs

https://github.com/RobotWebTools/roslibjs/tree/develop

  • Install roslibjs
npm install roslib
  • Alternatively, use one of the pre-build v1 files (CDN):
<script src="https://cdn.jsdelivr.net/npm/roslib@1/build/roslib.js"></script>
<script src="https://cdn.jsdelivr.net/npm/roslib@1/build/roslib.min.js"></script>
  • Add a simple webpage- Create a robot_gui_bridge/gui/gui.html file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
 
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/roslib@1/build/roslib.min.js"></script>
 
<script type="text/javascript" type="text/javascript">
  var ros = new ROSLIB.Ros({
    url : 'ws://localhost:9090'
  });
 
  ros.on('connection', function() {
    document.getElementById("status").innerHTML = "Connected";
  });
 
  ros.on('error', function(error) {
    document.getElementById("status").innerHTML = "Error";
  });
 
  ros.on('close', function() {
    document.getElementById("status").innerHTML = "Closed";
  });
</script>
</head>
 
<body>
  <h1>Simple ROS User Interface</h1>
  <p>Connection status: <span id="status"></span></p>
  <p>Last /txt_msg received: <span id="msg"></span></p>
</body>
</html>

Listening to a ROS Topic

  • subscribe to a topic /txt_msg that publishes std_msgs/String messages and display them in the browser.
var txt_listener = new ROSLIB.Topic({
  ros : ros,
  name : '/txt_msg',
  messageType : 'std_msgs/String'
});
 
txt_listener.subscribe(function(m) {
  document.getElementById("msg").innerHTML = m.data;
});
  • We create a txt_listener object that listens to the /txt_msg topic.
  • When a message is received, the event listener updates the HTML element with the id msg to show the message content.

Testing the Code

  • Launch the WebSocket

    roslaunch robot_gui_bridge websocket.launch
  • Open the Webpage

    • Open the gui.html file in your browser.
    • You should see the text “Connected” in the connection status.
  • Publish to the /txt_msg Topic**

ros2 topic pub /txt_msg std_msgs/msg/String "{data'Test message'}" --once

picture 0

Publishing on a Topic

Before we implement a virtual joystick, let’s create a function that we will use to publish a robot velocity:

cmd_vel_listener = new ROSLIB.Topic({
  ros : ros,
  name : "/cmd_vel",
  messageType : 'geometry_msgs/Twist'
});
 
move = function (linear, angular) {
  var twist = new ROSLIB.Message({
    linear: {
      x: linear,
      y: 0,
      z: 0
    },
    angular: {
      x: 0,
      y: 0,
      z: angular
    }
  });
  cmd_vel_listener.publish(twist);
}

Similarly to when we declared our String listener, we start by creating a Topic object called cmd_vel_listener that will be publishing Twist messages on the /cmd_vel topic. Afterwards, we create a function called move that takes two arguments: a linear and angular speed (by ROS convention in m/s) and publishes it through our cmd_vel_listener object.

To test what we have so far, you can modify the txt_listener event handler to publish a fixed velocity whenever it receives data:

txt_listener.subscribe(function(m) {
  document.getElementById("msg").innerHTML = m.data;
  move(1, 0);
});

To test it, simply run the following in a terminal:

ros2 topic echo /cmd_vel
  • send some messages to the /txt_msg topic to see the velocity messages being published.
ros2 topic pub /txt_msg std_msgs/msg/String "{data: 'Test message'}" --once
linear:
  x: 1.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0

Virtual Joystick

Warning

The library is loaded from Cloudflare CDN for simplicity, but you might want to serve the file yourself

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/nipplejs/0.7.3/nipplejs.js"></script>

2. Add the Joystick Container:

Add a <div> element to hold the virtual joystick in the body of webpage:

<div id="zone_joystick" style="position: relative;"></div>

3. Instantiate the Joystick and Handle Events:

instantiate the joystick and handle events like movement start, the movement itself, and the end of movement:

createJoystick = function () {
  var options = {
    zone: document.getElementById('zone_joystick'),
    threshold: 0.1,
    position: { left: '50%' },
    mode: 'static',
    size: 150,
    color: '#000000',
  };
  manager = nipplejs.create(options);
 
  linear_speed = 0;
  angular_speed = 0;
 
  manager.on('start', function (event, nipple) {
    console.log("Movement start");
  });
 
  manager.on('move', function (event, nipple) {
    console.log("Moving");
  });
 
  manager.on('end', function () {
    console.log("Movement end");
  });
}
 
window.onload = function () {
  createJoystick();
}

This snippet declares a createJoystick function that is called when the window is loaded. We set up options for the joystick and event handlers for start, move, and end events.

picture 0

4. Handling the Start Event:

Start a timer that calls the move function at a 25Hz rate:

manager.on('start', function (event, nipple) {
  timer = setInterval(function () {
    move(linear_speed, angular_speed);
  }, 25);
});

This ensures that the robot’s velocity command is sent continuously while the joystick is active.

5. Handling the End Event:

Clear the timer and send a stop command when the joystick movement ends:

manager.on('end', function () {
  if (timer) {
    clearInterval(timer);
  }
  move(0, 0); // Stop the robot
});

6. Handling Joystick Movement:

  • Joystick inputs are converted from polar coordinates (distance and angle) to linear velocity (forward movement) and angular velocity (rotation)
    • linear_speed is determined by the sine of the angle and scaled based on the joystick’s distance.
    • angular_speed is determined by the cosine of the angle and similarly scaled.
  • The joystick’s maximum distance is 75 pixels, and the maximum robot velocities are defined as 5 m/s for linear and 2 rad/s for angular.
manager.on('move', function (event, nipple) {
  max_linear = 5.0; // Max linear velocity (m/s)
  max_angular = 2.0; // Max angular velocity (rad/s)
  max_distance = 75.0; // Max joystick distance (pixels)
 
  linear_speed = Math.sin(nipple.angle.radian) * max_linear * nipple.distance / max_distance;
  angular_speed = -Math.cos(nipple.angle.radian) * max_angular * nipple.distance / max_distance;
});
  • The joystick should now be able to control a robot’s velocity via ROS2 velocity commands published on /cmd_vel
  • You can now control a robot’s movement by converting joystick inputs into ROS 2 velocity commands.

Conclusion

By implementing the virtual joystick using nipple.js, you can control a robot’s movement by converting joystick inputs into ROS 2 velocity commands. This approach ensures smooth control with adjustable speed limits.

sudo apt install ros-humble-plotjuggler

Plotjuggler

  • Install plotjuggler
sudo apt install ros-humble-plotjuggler
sudo apt install ros-humble-plotjuggler-ros
chmod 700 /run/user/1000/
  • Run plotjuggler
ros2 run plotjuggler plotjuggler

ros2 topic subscriber click topic name

picture 1