ROS 2 ros2_control package for simulating and interfacing a BlueROV2 Heavy + Reach Alpha 5 UVMS.
Exported package name: ros2_control_blue_reach_5
- Simulated and hardware-backed
ros2_controlsystem interfaces - Multi-robot UVMS spawning
- CasADi-backed vehicle and manipulator dynamics
- RViz, TF, rosbag, PlotJuggler, and HIL launch utilities
- Per-robot combined reset and release services for simulated UVMS robots
- Batched CPU/GPU UVMS core for large-N simulation and RL training through
uvms_rl
- Ubuntu with ROS 2 Jazzy
colcon,rosdep,vcs- CasADi built from source using the upstream instructions: https://github.com/casadi/casadi/wiki/SourceBuild
Core dependencies:
sudo apt update
sudo apt install git-lfs \
ros-$ROS_DISTRO-hardware-interface \
ros-$ROS_DISTRO-xacro \
ros-$ROS_DISTRO-gpio-controllers \
ros-$ROS_DISTRO-controller-manager \
ros-$ROS_DISTRO-joint-state-broadcaster \
ros-$ROS_DISTRO-joint-state-publisher-gui \
ros-$ROS_DISTRO-forward-command-controller \
ros-$ROS_DISTRO-force-torque-sensor-broadcaster \
ros-$ROS_DISTRO-ros2-control \
ros-$ROS_DISTRO-mavros \
ros-$ROS_DISTRO-mavros-msgs \
ros-$ROS_DISTRO-nav2-msgs \
ros-$ROS_DISTRO-rviz-imu-plugin \
ros-$ROS_DISTRO-rviz-2d-overlay-plugins \
ros-$ROS_DISTRO-rviz-2d-overlay-msgs \
ros-$ROS_DISTRO-rosbag2 \
gstreamer1.0-plugins-base \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-devPython dependencies used by SimLab and the simulated camera renderer:
python3 -m pip install pyPS4Controller pynput scipy casadi ruckig \
python-fcl trimesh pycollada pyvista open3dInstall PlotJuggler from Snap for the newer MCAP and scripting support used by the launch workflow:
sudo snap install plotjugglerThe main launch file starts /snap/bin/plotjuggler when
launch_plotjuggler:=true. If ros-$ROS_DISTRO-plotjuggler-ros is also
installed, it can remain installed; the launch file does not use that older
executable.
After installing CasADi, make sure its shared libraries are on the runtime linker path. If CasADi is outside the default linker path:
export LD_LIBRARY_PATH=/path/to/casadi/build/lib:$LD_LIBRARY_PATHcd ~/ros_ws/src
git clone https://github.com/edxmorgan/uvms-simulator.git
vcs import < uvms-simulator/dependency_repos.repos
cd ..
rosdep install --from-paths src --ignore-src -r -y
colcon build
source install/setup.bashSimulated UVMS:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py \
sim_robot_count:=1 \
task:=interactive \
use_manipulator_hardware:=false \
use_vehicle_hardware:=falseOther modes:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py task:=manual
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py task:=joint
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py task:=direct_thrustersHeadless recording:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py \
gui:=false \
task:=manual \
record_data:=truegui:=false disables GUI applications, including RViz, RViz overlays, and
PlotJuggler. Use launch_rviz:=false when you only want to suppress RViz while
leaving other GUI tools controlled by their own launch flags.
PlotJuggler:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py \
sim_robot_count:=1 \
task:=interactive \
launch_plotjuggler:=trueThe launch file starts /snap/bin/plotjuggler, so the Snap release is used
instead of the older ROS package executable. Plot live topics such as
/dynamic_joint_states, /<prefix>/reference/targets, and
/<prefix>/performance/controller. For recorded experiments, open the
~/ros_ws/recordings/mcap/uvms_bag_YYYYmmdd_HHMMSS MCAP bag in PlotJuggler.
Hardware-in-the-loop:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py \
use_manipulator_hardware:=true \
use_vehicle_hardware:=trueThe main launch file uses serial_port:=auto by default for the Reach Alpha manipulator. Auto mode tries /dev/serial/by-id/*, /dev/ttyUSB*, then /dev/ttyACM*. If the manipulator is on a known device, pass it explicitly:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py \
use_manipulator_hardware:=true \
use_vehicle_hardware:=false \
serial_port:=/dev/ttyUSB1Camera launch arguments:
launch_camera:=true: default. Starts the selected camera path.launch_camera:=false: disables camera nodes.launch_camera:=auto: starts the selected camera path whencamera_sourceresolves tosim,real, or mixed real/sim camera sources.camera_source:=auto: default. Uses the simulated renderer for simulated vehicles, the real GStreamer camera for real vehicle hardware, and mixed selection when real vehicle hardware and simulated robots are launched together.camera_source:=sim: forces the simulated renderer to publish/alpha/image_raw.camera_source:=real: forces the GStreamer camera node to publish/alpha/image_raw.camera_pipeline:="": optional custom GStreamer pipeline. If set, it overrides the default pipeline. The pipeline must end withappsink name=camera_sink.sim_camera_renderer_backend:=pyvista: default simulated renderer backend. Useopen3dfor comparison or fallback.sim_camera_render_all_cameras:=true: renders every simulated robot camera. Setfalseto render only the selected feed for lower load.sim_camera_underwater_effect:=true: applies the underwater tint/haze only when the simulated camera is below the water surface. Setfalsefor raw geometry/debug views.
The vehicle hardware interface starts the camera automatically:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py \
use_vehicle_hardware:=trueUse the camera without the vehicle hardware interface:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py \
use_manipulator_hardware:=true \
use_vehicle_hardware:=false \
task:=manual \
launch_camera:=true \
camera_source:=realUse the simulated camera renderer:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py \
use_vehicle_hardware:=false \
sim_robot_count:=1 \
task:=interactive \
camera_source:=simThe selected camera publishes sensor_msgs/msg/Image on /alpha/image_raw. RViz adds an enabled video feed Image display whenever camera launch is enabled. To verify images are arriving:
ros2 topic hz /alpha/image_rawIn mixed real/sim launches, per-robot camera topics are also available, for example /robot_real/camera/image_raw and /robot_1/camera/image_raw. Selecting a robot in the interactive menu updates the selected /alpha feed.
Camera intrinsics are published on the matching sensor_msgs/msg/CameraInfo topic, for example /alpha/camera_info or /robot_1/camera/camera_info. Camera extrinsics are provided through TF, for example world -> robot_1_camera_link or robot_1_base_link -> robot_1_camera_link.
Run only the standalone camera node:
ros2 run ros2_control_blue_reach_5 gstreamer_camera_node --ros-args \
-p image_topic:=/alpha/image_raw \
-p frame_id:=camera_linkReset simulated robot_1_:
ros2 service call /robot_1_reset_sim_uvms std_srvs/srv/TriggerRelease commands after reset:
ros2 service call /robot_1_release_sim_uvms std_srvs/srv/TriggerList available endpoints:
ros2 service list | grep -E 'reset_sim|release_sim'Low-level services are still available when needed:
ros2 service call /robot_1_reset_sim_manipulator std_srvs/srv/Trigger
ros2 service call /robot_1_reset_sim_vehicle std_srvs/srv/Trigger
ros2 service call /robot_1_release_sim_manipulator std_srvs/srv/Trigger
ros2 service call /robot_1_release_sim_vehicle std_srvs/srv/TriggerThe simulated manipulator exposes runtime payload and gravity state through ${prefix}_arm_IOs:
gravitypayload.masspayload.Ixxpayload.Iyypayload.Izz
Update simulator dynamics online with the coordinated per-robot service:
ros2 service call /robot_1_set_sim_uvms_dynamics ros2_control_blue_reach_5/srv/SetSimDynamics \
"{use_coupled_dynamics: false, set_vehicle_dynamics: false, set_manipulator_dynamics: true, manipulator: {gravity_vector: [0.0, 0.0, 9.81], payload_mass: 0.15, payload_inertia: [0.0, 0.0, 0.0]}}"Notes:
- The coordinated service forwards selected manipulator parameters to
/${prefix}set_sim_manipulator_dynamicsand vehicle parameters to/${prefix}set_sim_vehicle_dynamics. - The runtime RViz
Dynamics Profilemenu applies named whole-robot profiles through the same coordinated service. gravityis used directly by the current sim manipulator dynamics path.payload.massis used directly by the current sim manipulator dynamics path.gravityis also exported through${prefix}_arm_IOsfor downstream consumers such asuvms-simlab.payload.Ixx,payload.Iyy, andpayload.Izzare exported as live state and can be updated online, but they are not yet consumed by the current dynamics model.- Reset requests can carry typed vehicle and manipulator dynamics parameters. Replay profiles and the RViz
Dynamics Profilemenu use this path to apply named robot dynamics profiles.
interactive,manual, and several operator-facing workflows depend on the companion packageuvms_simlab.- Reset and release services are per robot prefix, for example
robot_2_androbot_3_. - Reset holds commands until the matching release service is called.
SimReachSystemMultiInterfaceHardwareReachSystemMultiInterfaceHardwareSimVehicleSystemMultiInterfaceHardwareBlueRovSystemMultiInterfaceHardware
- User guide:
doc/userdoc.rst - HIL notes:
doc/hil_setup.rst - Companion tools: https://github.com/edxmorgan/uvms-simlab
- https://github.com/edxmorgan/diff_uv
- https://github.com/edxmorgan/floating-KinDyn
- https://control.ros.org
AGPL-3.0-or-later
