From 1dfd0c750d18560fd4b86e625a7748d6d174dae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Ag=C3=BCero?= Date: Wed, 16 Sep 2026 15:54:27 +0200 Subject: [PATCH 1/2] Say that the launch names the instance and that the thruster topics follow it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Carlos Agüero Assisted-by: Claude Fable 5.1 --- docs/how-to/namespaces.md | 16 +++++++++------- docs/vehicles/blueboat/actuators.md | 13 ++++++++----- docs/vehicles/blueboat/sensors.md | 2 +- docs/vehicles/bluerov2/actuators.md | 15 +++++++++------ docs/vehicles/bluerov2/sensors.md | 16 ++++++++-------- 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/docs/how-to/namespaces.md b/docs/how-to/namespaces.md index a7dd631..83fc684 100644 --- a/docs/how-to/namespaces.md +++ b/docs/how-to/namespaces.md @@ -4,16 +4,18 @@ Every instance of a vehicle goes by one name, which is at once its Gazebo model name and its topic namespace (`//...` for every sensor and -thruster topic, on both the Gazebo and the ROS side). By default the name is -the config's `topic_namespace` (`blueboat` or `bluerov2`). A name is letters, +thruster topic, on both the Gazebo and the ROS side). A name is letters, digits and underscores, starting with a letter, because it also has to be a valid ROS name; the generator refuses anything else. -`name:=` on the sim launch is passed to `configure_vehicle.py --name`, which -applies it to the config before generating the artifacts (the config actually -used is written next to them as `vehicle.yaml`), so the model name, the -plugin topics and the bridge cannot disagree. `x`, `y`, `z`, `roll`, `pitch` -and `yaw` place the instance: +The launch argument is the name. `sim.launch.xml` always passes `name:=`, +`blueboat` or `bluerov2` by default, to `configure_vehicle.py --name`, which +applies it to the config before generating the artifacts (the config +actually used is written next to them as `vehicle.yaml`), so the model +name, the plugin topics and the bridge cannot disagree. A `topic_namespace` +in a custom config is therefore overridden by the launch; it only names the +instance when the generator runs without `--name`. `x`, `y`, `z`, `roll`, +`pitch` and `yaw` place the instance: ```bash ros2 launch blueboat_gazebo sim.launch.xml name:=boat_b x:=4 yaw:=1.57 diff --git a/docs/vehicles/blueboat/actuators.md b/docs/vehicles/blueboat/actuators.md index 829ba93..c4f2e6a 100644 --- a/docs/vehicles/blueboat/actuators.md +++ b/docs/vehicles/blueboat/actuators.md @@ -18,12 +18,15 @@ following the [Add a part](../../how-to/add-part.md) guide. ### Thrusters Each thruster plugin subscribes to a gz transport topic. Each of those gz -topics is bridged to ROS and named after its motor: +topics is bridged to ROS and named after its motor, under the instance +name, ``: `blueboat` for the default instance, which the commands +below use, or whatever the boat was spawned as +([Several vehicles](../../how-to/namespaces.md)). | ROS Topic | Description | Message type | |---|---|---| -| `/blueboat/motor_port/cmd` | Normalized thrust command in [-1, 1]: +1 full ahead, -1 full astern, 0 stop | [std_msgs/msg/Float64](https://docs.ros.org/en/rolling/p/std_msgs/interfaces/msg/Float64.html) | -| `/blueboat/motor_stbd/cmd` | Normalized thrust command in [-1, 1]: +1 full ahead, -1 full astern, 0 stop | [std_msgs/msg/Float64](https://docs.ros.org/en/rolling/p/std_msgs/interfaces/msg/Float64.html) | +| `//motor_port/cmd` | Normalized thrust command in [-1, 1]: +1 full ahead, -1 full astern, 0 stop | [std_msgs/msg/Float64](https://docs.ros.org/en/rolling/p/std_msgs/interfaces/msg/Float64.html) | +| `//motor_stbd/cmd` | Normalized thrust command in [-1, 1]: +1 full ahead, -1 full astern, 0 stop | [std_msgs/msg/Float64](https://docs.ros.org/en/rolling/p/std_msgs/interfaces/msg/Float64.html) | The command is a fraction of the propeller's own limits, which the model takes from the part's drive table - 51.5 N ahead and -40.2 N astern for a @@ -61,8 +64,8 @@ under the same names), plus a speed feedback per motor: | gz Topic | Description | Message type | |---|---|---| -| `/blueboat/motor_/cmd` | Normalized thrust command in [-1, 1] | `gz.msgs.Double` | -| `/blueboat/motor_/cmd/ang_vel` | Propeller speed feedback (rad/s) | `gz.msgs.Double` | +| `//motor_/cmd` | Normalized thrust command in [-1, 1] | `gz.msgs.Double` | +| `//motor_/cmd/ang_vel` | Propeller speed feedback (rad/s) | `gz.msgs.Double` | ```bash gz topic -t /blueboat/motor_port/cmd -m gz.msgs.Double -p 'data: 0.2' & diff --git a/docs/vehicles/blueboat/sensors.md b/docs/vehicles/blueboat/sensors.md index 9e069de..6953123 100644 --- a/docs/vehicles/blueboat/sensors.md +++ b/docs/vehicles/blueboat/sensors.md @@ -23,7 +23,7 @@ starboard hull. | ROS Topic | Description | Message type | |---|---|---| -| `/blueboat/ping/range` | Range to the seabed; bridged lazily, the Gazebo subscription starts with the first ROS subscriber | [sensor_msgs/msg/LaserScan](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/LaserScan.html) | +| `//ping/range` | Range to the seabed; bridged lazily, the Gazebo subscription starts with the first ROS subscriber | [sensor_msgs/msg/LaserScan](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/LaserScan.html) | ```bash ros2 topic echo /blueboat/ping/range --once diff --git a/docs/vehicles/bluerov2/actuators.md b/docs/vehicles/bluerov2/actuators.md index 0b36fb1..6791bb7 100644 --- a/docs/vehicles/bluerov2/actuators.md +++ b/docs/vehicles/bluerov2/actuators.md @@ -27,11 +27,14 @@ Thruster numbering, top view. ``` Each thruster plugin subscribes to a gz transport topic. Each of those gz -topics is bridged to ROS and indexed by number, starting at 1: +topics is bridged to ROS and indexed by number, starting at 1, under the +instance name, ``: `bluerov2` for the default instance, which the +commands below use, or whatever the vehicle was spawned as +([Several vehicles](../../how-to/namespaces.md)). | ROS Topic | Description | Message type | |---|---|---| -| `/bluerov2/thruster_/cmd` | Normalized thrust command in [-1, 1]: +1 full ahead, -1 full astern, 0 stop | [std_msgs/msg/Float64](https://docs.ros.org/en/rolling/p/std_msgs/interfaces/msg/Float64.html) | +| `//thruster_/cmd` | Normalized thrust command in [-1, 1]: +1 full ahead, -1 full astern, 0 stop | [std_msgs/msg/Float64](https://docs.ros.org/en/rolling/p/std_msgs/interfaces/msg/Float64.html) | The command is a fraction of the propeller's own limits, which the model takes from the part's drive table - 51.5 N ahead and -40.2 N astern for a @@ -75,7 +78,7 @@ thrusters. | ROS Topic | Description | Message type | |---|---|---| -| `/bluerov2/gripper/cmd_pos` | Jaw angle command, 0 rad closed to 0.6 rad open | [std_msgs/msg/Float64](https://docs.ros.org/en/rolling/p/std_msgs/interfaces/msg/Float64.html) | +| `//gripper/cmd_pos` | Jaw angle command, 0 rad closed to 0.6 rad open | [std_msgs/msg/Float64](https://docs.ros.org/en/rolling/p/std_msgs/interfaces/msg/Float64.html) | To drive with a gamepad instead, a ready mixer for either vehicle is in @@ -88,9 +91,9 @@ under the same names), plus a speed feedback per thruster: | gz Topic | Description | Message type | |---|---|---| -| `/bluerov2/thruster_/cmd` | Normalized thrust command in [-1, 1] | `gz.msgs.Double` | -| `/bluerov2/thruster_/cmd/ang_vel` | Propeller speed feedback (rad/s) | `gz.msgs.Double` | -| `/bluerov2/gripper/cmd_pos` | Jaw angle command | `gz.msgs.Double` | +| `//thruster_/cmd` | Normalized thrust command in [-1, 1] | `gz.msgs.Double` | +| `//thruster_/cmd/ang_vel` | Propeller speed feedback (rad/s) | `gz.msgs.Double` | +| `//gripper/cmd_pos` | Jaw angle command | `gz.msgs.Double` | Command the mix **together** (`&` + `wait` publishes in parallel): diff --git a/docs/vehicles/bluerov2/sensors.md b/docs/vehicles/bluerov2/sensors.md index 1753383..7c2b59a 100644 --- a/docs/vehicles/bluerov2/sensors.md +++ b/docs/vehicles/bluerov2/sensors.md @@ -22,29 +22,29 @@ live with the [actuators](actuators.md). | ROS Topic | Description | Message type | |---|---|---| -| `/bluerov2/camera/image` | Camera image | [sensor_msgs/msg/Image](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/Image.html) | -| `/bluerov2/camera/camera_info` | Camera intrinsics | [sensor_msgs/msg/CameraInfo](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/CameraInfo.html) | +| `//camera/image` | Camera image | [sensor_msgs/msg/Image](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/Image.html) | +| `//camera/camera_info` | Camera intrinsics | [sensor_msgs/msg/CameraInfo](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/CameraInfo.html) | ### Stereo camera | ROS Topic | Description | Message type | |---|---|---| -| `/bluerov2/stereo/image` | RGB image | [sensor_msgs/msg/Image](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/Image.html) | -| `/bluerov2/stereo/depth_image` | Depth image | [sensor_msgs/msg/Image](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/Image.html) | -| `/bluerov2/stereo/points` | Point cloud | [sensor_msgs/msg/PointCloud2](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/PointCloud2.html) | -| `/bluerov2/stereo/camera_info` | Camera intrinsics | [sensor_msgs/msg/CameraInfo](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/CameraInfo.html) | +| `//stereo/image` | RGB image | [sensor_msgs/msg/Image](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/Image.html) | +| `//stereo/depth_image` | Depth image | [sensor_msgs/msg/Image](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/Image.html) | +| `//stereo/points` | Point cloud | [sensor_msgs/msg/PointCloud2](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/PointCloud2.html) | +| `//stereo/camera_info` | Camera intrinsics | [sensor_msgs/msg/CameraInfo](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/CameraInfo.html) | ### Scanning sonar | ROS Topic | Description | Message type | |---|---|---| -| `/bluerov2/sonar/scan` | Horizontal range scan (modelled as a planar gpu_lidar; no acoustics) | [sensor_msgs/msg/LaserScan](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/LaserScan.html) | +| `//sonar/scan` | Horizontal range scan (modelled as a planar gpu_lidar; no acoustics) | [sensor_msgs/msg/LaserScan](https://docs.ros.org/en/rolling/p/sensor_msgs/interfaces/msg/LaserScan.html) | ### DVL | ROS Topic | Description | Message type | |---|---|---| -| `/bluerov2/dvl/velocity` | Bottom track velocity | [marine_acoustic_msgs/msg/Dvl](https://github.com/apl-ocean-engineering/hydrographic_msgs/blob/main/marine_acoustic_msgs/msg/Dvl.msg) | +| `//dvl/velocity` | Bottom track velocity | [marine_acoustic_msgs/msg/Dvl](https://github.com/apl-ocean-engineering/hydrographic_msgs/blob/main/marine_acoustic_msgs/msg/Dvl.msg) | Topic bases follow `///...`: empty a slot and its topics disappear, rename the instance and they follow, and per part From 61c8b7c2738fe50e40fdb38fc06e4150684cb211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Ag=C3=BCero?= Date: Wed, 16 Sep 2026 16:13:23 +0200 Subject: [PATCH 2/2] Use one instance name placeholder and heading anchor links across the docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Carlos Agüero Assisted-by: Claude Fable 5.1 --- docs/conf.py | 4 ++++ docs/design/buoyancy.md | 2 -- docs/design/gazebo-composition.md | 4 ++-- docs/how-to/change-parts.md | 2 +- docs/how-to/own-world.md | 2 +- docs/reference/parts-catalog.md | 3 +-- docs/vehicles/blueboat/actuators.md | 6 +++--- docs/vehicles/blueboat/configuration.md | 2 +- docs/vehicles/blueboat/sensors.md | 16 ++++++++-------- docs/vehicles/bluerov2/configuration.md | 2 +- docs/vehicles/bluerov2/sensors.md | 15 ++++++++------- 11 files changed, 30 insertions(+), 28 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 17e2698..4a34a67 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,4 +17,8 @@ author = 'Honu Robotics' extensions = ['sphinx_honu'] + +# Anchors for headings down to ###, so a page can link to a section +# (`page.md#section-title`) in a way GitHub renders too. +myst_heading_anchors = 3 honu_github = ('HonuRobotics', 'bluerobotics_models') diff --git a/docs/design/buoyancy.md b/docs/design/buoyancy.md index 51477f4..5b429f1 100644 --- a/docs/design/buoyancy.md +++ b/docs/design/buoyancy.md @@ -54,8 +54,6 @@ contact geometry. The box itself never collides (`collide_bitmask` `0x00`). The same pattern as the BlueBoat's pontoons, with the box solved instead of declared. -(marked-for-any-world)= - ## Marked for any world The displacement collisions of both vehicles carry `gz:buoyancy="true"`. diff --git a/docs/design/gazebo-composition.md b/docs/design/gazebo-composition.md index 66a0755..78a8e2f 100644 --- a/docs/design/gazebo-composition.md +++ b/docs/design/gazebo-composition.md @@ -48,7 +48,7 @@ side never held a coordinate. `generate_bridge_config.py` reads the fitted instances from the URDF's `` manifest and emits one bridge entry per topic of each part type that has topics (`PART_TOPICS`: a propeller's `/cmd` command, -the Ping's `/range`), plus `/clock` and `//joint_states`; per instance topic +the Ping's `/range`), plus `/clock` and `//joint_states`; per instance topic overrides come from the config entry that fitted it. Nothing about the drivetrain is hardcoded and no topic bakes the model name. The model's plugin and sensor topics and the bridge's topics therefore derive from the @@ -78,5 +78,5 @@ launch. | `hull_displacement` link | box pontoons from the config; `blueboat::hull_displacement` in the world | | `gz-sim-hydrodynamics-system` | placeholder USV damping coefficients, to be identified | | `gz-maritime-thruster-system`, one per propeller | on `_joint`, normalized command scaled onto the limits and diameter from the part's `drive` table (T200 16 V placeholders today), counter rotating | -| `gz-sim-joint-state-publisher-system` | `//joint_states`, bridged for RViz | +| `gz-sim-joint-state-publisher-system` | `//joint_states`, bridged for RViz | | `gpu_lidar` "ping" | the Ping2 as a one ray downward range sensor at `ping_beam` | diff --git a/docs/how-to/change-parts.md b/docs/how-to/change-parts.md index e50b6af..0e911f6 100644 --- a/docs/how-to/change-parts.md +++ b/docs/how-to/change-parts.md @@ -2,7 +2,7 @@ Recipes for the vehicle config. The concepts (slots, defaults, free placement) are explained in [Configuring the BlueBoat](../vehicles/blueboat/configuration.md); -the full key list is in {ref}`Configuration keys `. +the full key list is in [Configuration keys](../reference/parts-catalog.md#configuration-keys). Start from a copy of the shipped config: diff --git a/docs/how-to/own-world.md b/docs/how-to/own-world.md index c05256b..2d00f57 100644 --- a/docs/how-to/own-world.md +++ b/docs/how-to/own-world.md @@ -16,7 +16,7 @@ cp $(ros2 pkg prefix --share blueboat_gazebo)/worlds/blueboat_water.sdf my_world A world running gz-maritime's buoyancy system needs no `` entry: the displacement collisions are marked, so the vehicle floats under any -spawn name ({ref}`Marked for any world `). +spawn name ([Marked for any world](../design/buoyancy.md#marked-for-any-world)). ## Include the default model diff --git a/docs/reference/parts-catalog.md b/docs/reference/parts-catalog.md index 630b75c..66b8909 100644 --- a/docs/reference/parts-catalog.md +++ b/docs/reference/parts-catalog.md @@ -68,7 +68,6 @@ after the slot by default. `thruster_8` and `thruster_body_1` … `thruster_body_8` and keeps the same accessory slots. -(configuration-keys)= ## Configuration keys The vehicle config (`_description/config/.yaml`, or any @@ -77,7 +76,7 @@ for both vehicles: | Key | Required | Meaning | |---|---|---| -| `topic_namespace` | no (the vehicle name) | prefix of every part topic: `///...` | +| `topic_namespace` | no (the vehicle name) | prefix of every part topic: `///...` | | `base` | yes | the root part: `{type, name (default base_link), collision (default true)}` | | `parts` | no (`[]`) | slot entries and free placements, see below | | `slots` | no | ad hoc slots: `{of (instance, default base_link), name, xyz, rpy (default "0 0 0"), accepts (list, optional), default (type or none), joint}` | diff --git a/docs/vehicles/blueboat/actuators.md b/docs/vehicles/blueboat/actuators.md index c4f2e6a..128dd13 100644 --- a/docs/vehicles/blueboat/actuators.md +++ b/docs/vehicles/blueboat/actuators.md @@ -73,6 +73,6 @@ gz topic -t /blueboat/motor_stbd/cmd -m gz.msgs.Double -p 'data: 0.2' & wait ``` -Topic bases follow `///...`: fit a different -propeller, rename it or leave a motor slot empty and the command topics -follow the fitted parts. +A command topic follows the part's own name: fit a different propeller, +rename it or leave a motor slot empty and the topics follow the fitted +parts ([Configuration](configuration.md)). diff --git a/docs/vehicles/blueboat/configuration.md b/docs/vehicles/blueboat/configuration.md index 4589dca..a3356e6 100644 --- a/docs/vehicles/blueboat/configuration.md +++ b/docs/vehicles/blueboat/configuration.md @@ -31,7 +31,7 @@ config entry each. The fitted options and their topics live in | `ping_mount` | `blueboat_ping_singlebeam_mount` | the bracket (which fits the Ping in its own `ping` slot) | Slot entries, free placements, ad hoc slots and topic overrides are -described in the {ref}`Configuration keys ` and +described in the [Configuration keys](../../reference/parts-catalog.md#configuration-keys) and walked through in [Change the fitted parts](../../how-to/change-parts.md); the instance key is `of:`, not `on:`. Mistakes fail the build or the launch with a message naming the problem. diff --git a/docs/vehicles/blueboat/sensors.md b/docs/vehicles/blueboat/sensors.md index 6953123..4f388a9 100644 --- a/docs/vehicles/blueboat/sensors.md +++ b/docs/vehicles/blueboat/sensors.md @@ -29,11 +29,11 @@ starboard hull. ros2 topic echo /blueboat/ping/range --once ``` -Topic bases follow `///...`: empty a slot and its -topics disappear, rename the instance and they follow, and per part -`topic` / `gz_topic` / `ros_topic` overrides in the config rename the -base under the namespace (one starting with a slash is used as given). -Sensor messages carry a frame the part declares as `frame_id` -(`ping_beam`, the transducer face), under the instance name -(`blueboat/ping_beam`), which is how TF carries it. Rendered sensors need -a GPU (headless EGL works). +`` is the instance name, `blueboat` for the default instance, or +whatever the boat was spawned as ([Several vehicles](../../how-to/namespaces.md)). +A part topic follows the part's own name (`ping` above), so a part renamed +or removed in the config moves or drops its topics +([Configuration](configuration.md)). Sensor messages carry a frame the +part declares as `frame_id` (`ping_beam`, the transducer face), under the +instance name (`/ping_beam`), which is how TF carries it. Rendered +sensors need a GPU (headless EGL works). diff --git a/docs/vehicles/bluerov2/configuration.md b/docs/vehicles/bluerov2/configuration.md index af3ee27..67f4760 100644 --- a/docs/vehicles/bluerov2/configuration.md +++ b/docs/vehicles/bluerov2/configuration.md @@ -56,6 +56,6 @@ config entry each. The fitted options and their topics live in Slot entries, free placements, ad hoc slots and topic overrides follow the same schema as the BlueBoat -({ref}`Configuration keys `); the instance key is +([Configuration keys](../../reference/parts-catalog.md#configuration-keys)); the instance key is `of:`, not `on:`. Mistakes fail the build or the launch with a message naming the problem. diff --git a/docs/vehicles/bluerov2/sensors.md b/docs/vehicles/bluerov2/sensors.md index 7c2b59a..d5088e4 100644 --- a/docs/vehicles/bluerov2/sensors.md +++ b/docs/vehicles/bluerov2/sensors.md @@ -46,10 +46,11 @@ live with the [actuators](actuators.md). |---|---|---| | `//dvl/velocity` | Bottom track velocity | [marine_acoustic_msgs/msg/Dvl](https://github.com/apl-ocean-engineering/hydrographic_msgs/blob/main/marine_acoustic_msgs/msg/Dvl.msg) | -Topic bases follow `///...`: empty a slot and its -topics disappear, rename the instance and they follow, and per part -`topic` / `gz_topic` / `ros_topic` overrides in the config rename the -base under the namespace (one starting with a slash is used as given). -Sensor messages carry the part's own link as `frame_id`, under the -instance name (`bluerov2/camera`), which is how TF carries it; cameras deliberately use the body frame (x forward), not a -REP 145 optical frame. +`` is the instance name, `bluerov2` for the default instance, or +whatever the vehicle was spawned as ([Several vehicles](../../how-to/namespaces.md)). +A part topic follows the part's own name (`camera` above), so a part +renamed or removed in the config moves or drops its topics +([Configuration](configuration.md)). Sensor messages carry the part's own +link as `frame_id`, under the instance name (`/camera`), which is +how TF carries it; cameras deliberately use the body frame (x forward), +not a REP 145 optical frame.