This starts a WebSocket server provided by the rosbridge_server package.
The server runs as a node named rosbridge_websocket, listens on port 9090, and outputs logs to the terminal.
Modify CMakeLists.txt to install launch file
# CD into ros2_wscd ../../..# Copy and paste into CMakeLists.txtinstall( 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
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:
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.
4. Handling the Start Event:
Start a timer that calls the move function at a 25Hz rate:
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.