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 bringup utilities
- Per-robot combined reset and release services for simulated UVMS robots
- 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 \
ros-$ROS_DISTRO-plotjuggler-ros \
gstreamer1.0-plugins-base \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-devAfter 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 ~/ros2_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:=trueHardware-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:=auto: default. Starts the camera whenuse_vehicle_hardware:=trueorsimulate_camera:=true.launch_camera:=true: always starts the camera node.launch_camera:=false: disables the camera node.simulate_camera:=false: default. Uses the hardware UDP camera pipeline.simulate_camera:=true: uses a synthetic GStreamer test pattern and publishes it as/alpha/image_raw.camera_pipeline:="": optional custom GStreamer pipeline. If set, it overrides the default pipeline. The pipeline must end withappsink name=camera_sink.
Real vehicle hardware starts the camera automatically:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py \
use_vehicle_hardware:=trueUse the real camera without real vehicle hardware:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py \
use_manipulator_hardware:=true \
use_vehicle_hardware:=false \
sim_robot_count:=0 \
task:=manual \
launch_camera:=trueSimulate the camera when no camera hardware is connected:
ros2 launch ros2_control_blue_reach_5 robot_system_multi_interface.launch.py \
use_manipulator_hardware:=true \
use_vehicle_hardware:=false \
sim_robot_count:=0 \
task:=manual \
simulate_camera:=trueThe camera publishes sensor_msgs/msg/Image on /alpha/image_raw. RViz adds an enabled video feed Image display whenever the camera node is launched. To verify images are arriving:
ros2 topic hz /alpha/image_rawRun 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_linkRun only the standalone simulated camera:
ros2 run ros2_control_blue_reach_5 gstreamer_camera_node --ros-args \
-p image_topic:=/alpha/image_raw \
-p frame_id:=camera_link \
-p pipeline:='videotestsrc is-live=true pattern=ball ! video/x-raw,width=640,height=480,framerate=30/1 ! videoconvert ! video/x-raw,format=(string)BGR ! appsink name=camera_sink emit-signals=true sync=false async=false max-buffers=1 drop=true'Reset 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 the simulated manipulator dynamics online with the per-robot service:
ros2 service call /robot_1_set_sim_dynamics ros2_control_blue_reach_5/srv/SetSimDynamics \
"{gravity: 9.81, mass: 0.15, ixx: 0.0, iyy: 0.0, izz: 0.0}"Notes:
- This service is available for the simulated manipulator hardware interface.
- The service updates gravity and payload properties together from one endpoint.
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.- Resetting the simulated manipulator clears both gravity and payload values back to zero.
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
