Skip to content

Pre-comp dev merge#36

Open
osu-uwrt-bot2 wants to merge 15 commits into
masterfrom
dev
Open

Pre-comp dev merge#36
osu-uwrt-bot2 wants to merge 15 commits into
masterfrom
dev

Conversation

@osu-uwrt-bot2

@osu-uwrt-bot2 osu-uwrt-bot2 commented Jul 3, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features

    • Added controls to reset mapping and capture an image from the mapping panel.
    • Improved RViz marker and object visualization coverage with updated assets and frames.
    • Added higher-DPI support for on-screen overlays.
  • Bug Fixes

    • The interactive setpoint marker now stays hidden while autonomy is active.
    • Diagnostics handling is more robust and avoids crashes from unexpected data.
    • Parameter changes for array values are now detected and applied more reliably.
  • Style

    • Updated panel layouts, window sizing, and visualization defaults for a cleaner interface.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR updates RViz scene/marker configuration for the Talos robot, adds autonomy-aware interactive marker suppression in ControlPanel, introduces mapping reset/capture image services and UI in MappingPanel, adds TF broadcasting with base-link offset correction in MarkerPublisher, adds DPI-aware scaling to OverlayDisplay, fixes MissionPanel focus behavior, and reworks ParamPanel array-parameter change detection using stored widget properties.

Changes

RViz GUI and control panel changes

Layer / File(s) Summary
RViz scene/display configuration and marker meshes
riptide_rviz/control_config_talos.rviz, riptide_rviz/riptide_rviz/config/markers.yaml
Updates TF frame enablement/hierarchy, RobotModel links, point cloud/vision configuration, mapping object names/topics, view/window state, and marker mesh/frame assignments.
Autonomy tree stack integration
riptide_rviz/riptide_rviz/include/riptide_rviz/ControlPanel.hpp, riptide_rviz/riptide_rviz/src/ControlPanel.cpp
Adds a TreeStack subscriber and callback that toggles an autonomyActive flag to suppress/restore the interactive setpoint marker, and rewrites diagCallback to safely validate diagnostic message sizes.
MappingPanel reset/capture services and UI
riptide_rviz/riptide_rviz/include/riptide_rviz/MappingPanel.hpp, riptide_rviz/riptide_rviz/src/MappingPanel.cpp, riptide_rviz/riptide_rviz/src/MappingPanel.ui
Adds resetMapping()/captureImage() slots and Trigger service clients, wires new buttons, and reworks the panel's grid layout with new/relocated widgets.
MarkerPublisher TF broadcasting and offset
riptide_rviz/riptide_rviz/python/MarkerPublisher.py
Loads a per-robot base_link offset from config, rotates it into world frame, adjusts ghost marker position, and broadcasts ghost/base_link and ghost/origin TF transforms.
OverlayDisplay DPI scaling
riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp
Adds screen DPI-based scale factor computation, applies it to overlay texture sizing, and switches text rendering to pixel-size fonts.
MissionPanel focus fix
riptide_rviz/riptide_rviz/src/MissionPanel.cpp
Disables keyboard focus on the tree-select button to prevent unwanted highlighting.
ParamPanel array change detection
riptide_rviz/riptide_rviz/src/ParamPanel.cpp
Stores original array element values as widget properties and compares against them (instead of stylesheet state) to detect and apply modified array parameters.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TreeStackTopic
  participant ControlPanel
  participant InteractiveMarkerServer

  TreeStackTopic->>ControlPanel: treeStackCallback(TreeStack msg)
  alt stack not empty
    ControlPanel->>ControlPanel: autonomyActive = true
    ControlPanel->>InteractiveMarkerServer: erase setpoint marker
  else stack empty
    ControlPanel->>ControlPanel: autonomyActive = false
    ControlPanel->>InteractiveMarkerServer: reinsert + apply setpoint marker
  end
Loading
sequenceDiagram
  participant User
  participant MappingPanel
  participant ROSService

  User->>MappingPanel: click Reset Mapping button
  MappingPanel->>ROSService: resetMappingClient Trigger request
  User->>MappingPanel: click Capture Image button
  MappingPanel->>ROSService: captureImageClient Trigger request
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is a generic merge note and does not describe the main changes in the pull request. Use a concise, specific title that reflects the primary change, such as the main UI, marker, or control-panel update.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
riptide_rviz/control_config_talos.rviz (3)

1109-1126: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

"Table" entry in Mapping Objects points to a dummy-detection topic, not a mapping topic.

Every sibling entry in this "Mapping Objects" group (Gate, Pill, Plug, Bandage, Warning, Helmet, Sos, Hammer and Wrench, Buoy, Compass, Torpedo, Bin Target 1/2) subscribes to /talos/mapping/*. This "Table" entry instead uses /talos/dummydetections/table — the exact same topic used by the separate "Table" entry in the "Dummy Detections" group (line 2125). This looks like a copy-paste error; the fused mapping pose for the table will never be displayed here.

🔧 Suggested fix
           Topic:
             Depth: 5
             Durability Policy: Volatile
             Filter size: 10
             History Policy: Keep Last
             Reliability Policy: Reliable
-            Value: /talos/dummydetections/table
+            Value: /talos/mapping/table
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@riptide_rviz/control_config_talos.rviz` around lines 1109 - 1126, The “Table”
item in the Mapping Objects group is subscribed to the wrong topic and should
match the other mapping entries. Update the Topic value for the Table entry in
control_config_talos.rviz so it uses the mapping namespace instead of the
dummy-detections topic, aligning it with the other Mapping Objects entries and
avoiding duplication with the separate Table item in the Dummy Detections group.

2605-2651: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Duplicate topic: "Fire Hole Small" and "Fire Hole Large" both subscribe to the same "_large" topic.

Name: Fire Hole Small (line 2605) and Name: Fire Hole Large (line 2640) both use Value: /talos/dummydetections/torpedo_fire_hole_large. Compare with the correctly-differentiated sibling pair "Blood Hole Large"/"Blood Hole Small", which use distinct _large/_small topics. The "Fire Hole Small" display will never show actual small-hole detections, and both panels will duplicate the "large" hole data.

🐛 Suggested fix
           Topic:
             Depth: 5
             Durability Policy: Volatile
             Filter size: 10
             History Policy: Keep Last
             Reliability Policy: Reliable
-            Value: /talos/dummydetections/torpedo_fire_hole_large
+            Value: /talos/dummydetections/torpedo_fire_hole_small
           Value: true

(applies to the "Fire Hole Small" entry at line 2615; the "Fire Hole Large" entry at line 2650 can keep the _large topic)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@riptide_rviz/control_config_talos.rviz` around lines 2605 - 2651, The “Fire
Hole Small” display is subscribed to the same detection topic as “Fire Hole
Large,” so the small and large views duplicate the large-hole data. Update the
topic used by the Fire Hole Small entry in the rviz config to the corresponding
small-hole topic, following the pattern already used by the Blood Hole
Small/Large displays. Keep the Fire Hole Large entry on the _large topic and
verify the two Fire Hole displays reference distinct topics.

730-741: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Rename the gate mapping displays to match the new object names

Gate Shark/Gate Saw still use /talos/mapping/gate_shark and /talos/mapping/gate_saw here, while markers.yaml and the dummy-detections entries already use Gate Repair/Gate Rescue with gate_repair/gate_rescue. Update these two RViz entries to keep the mapping config consistent. [lines 730-741, 764-776]

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@riptide_rviz/control_config_talos.rviz` around lines 730 - 741, The RViz gate
mapping display entries are still using the old object names and topics, so
update the two display blocks in control_config_talos.rviz for the Gate
Shark/Gate Saw mappings to match the new naming used elsewhere. In the relevant
RViz entries, rename the display labels to Gate Repair and Gate Rescue and
change their Topic Value fields from the old gate_shark/gate_saw mappings to the
corresponding gate_repair/gate_rescue topics so the configuration stays
consistent with markers.yaml and the dummy-detections data.
🧹 Nitpick comments (3)
riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp (2)

115-116: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Typo in comment.

"JLog" should be "Log".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp` around lines 115 - 116, The
comment on logUiScale has a typo: “JLog” should be “Log”. Update the nearby
comment in OverlayDisplay.cpp so it correctly says “Log info about the ui
scaling,” keeping the function name logUiScale unchanged.

266-267: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Unused QFontMetrics fm left after removing text_rect computation.

fm is declared but no longer used since the bounding-rect computation was removed. This will trigger an unused-variable warning (and potential -Werror build failure depending on compiler flags).

🧹 Proposed fix
-            QStaticText only_wrapped_text(color_wrapped_text.c_str());
-            QFontMetrics fm(painter.fontMetrics());
+            QStaticText only_wrapped_text(color_wrapped_text.c_str());
             painter.drawStaticText(config.x_ + 1, config.y_ + 1, static_shadow);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp` around lines 266 - 267, The
OverlayDisplay::drawText path has an unused QFontMetrics fm declaration left
behind after removing the text_rect calculation, which can trigger warnings or
break builds with -Werror. Remove the redundant fm variable from the block that
creates only_wrapped_text, and keep the wrapping/rendering logic in
OverlayDisplay.cpp using only the symbols that are still needed.
riptide_rviz/riptide_rviz/src/MissionPanel.cpp (1)

29-31: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Qt::NoFocus removes keyboard access to the tree selector.

Setting btSelect (a QComboBox) to Qt::NoFocus prevents it from receiving keyboard focus at all — it can no longer be tabbed to or operated via keyboard, only by mouse click. If the intent is just to suppress the focus-rectangle highlight rather than block keyboard interaction entirely, consider Qt::ClickFocus combined with a stylesheet override (e.g., QComboBox:focus { outline: none; }) instead of Qt::NoFocus.

♻️ Suggested alternative preserving keyboard access
-        // dont want random highlighting of the tree list
-        uiPanel->btSelect->setFocusPolicy(Qt::NoFocus);
+        // dont want random highlighting of the tree list, but still allow keyboard use
+        uiPanel->btSelect->setFocusPolicy(Qt::ClickFocus);
+        uiPanel->btSelect->setStyleSheet("QComboBox:focus { outline: none; }");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@riptide_rviz/riptide_rviz/src/MissionPanel.cpp` around lines 29 - 31, The
focus setting on btSelect in MissionPanel is blocking keyboard navigation by
using Qt::NoFocus. Update the MissionPanel setup so the QComboBox can still
receive keyboard focus, and use a styling approach or a less restrictive focus
policy to suppress the visual focus highlight instead. Keep the change localized
to the btSelect configuration in MissionPanel.cpp.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@riptide_rviz/riptide_rviz/python/MarkerPublisher.py`:
- Around line 302-324: Avoid mutating the aliased pose in place in the marker
publishing path: in the logic around ghost pose handling, `ghost.pose` is shared
with `self.latestOdom.pose.pose` / `self.latestSetpt`, so subtracting the
rotated base-link offset directly changes the stored source message and causes
repeated drift on later ticks. Update `MarkerPublisher` so it copies the pose
into a fresh `Pose`/`Point` object before applying the `v_world` offset, and
then append that independent marker pose instead of modifying the original.

In `@riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp`:
- Around line 228-234: The font sizing in OverlayDisplay::paintText is not using
the same DPI scaling as the overlay dimensions, so text stays visually smaller
on high-DPI displays. Update the font setup in paintText to apply
getUiScaleFactor() consistently when calling QFont::setPixelSize, using the same
scale logic already used by updateWidth() and updateHeight(), and make sure the
other paintText occurrence uses the same adjusted sizing path.
- Around line 102-113: The UI scaling logic in getUiScaleFactor() is using
QGuiApplication::primaryScreen() and combining devicePixelRatio with
logicalDotsPerInch(), which can mis-scale overlays on multi-monitor setups.
Update the scale source to use the RViz render window’s owning screen/window
instead of the primary screen, and adjust the calculation so DPR and logical DPI
are not blindly merged unless there’s a platform-specific need. Keep the change
localized to getUiScaleFactor() in OverlayDisplay.cpp and preserve the existing
high-DPI fallback behavior.

---

Outside diff comments:
In `@riptide_rviz/control_config_talos.rviz`:
- Around line 1109-1126: The “Table” item in the Mapping Objects group is
subscribed to the wrong topic and should match the other mapping entries. Update
the Topic value for the Table entry in control_config_talos.rviz so it uses the
mapping namespace instead of the dummy-detections topic, aligning it with the
other Mapping Objects entries and avoiding duplication with the separate Table
item in the Dummy Detections group.
- Around line 2605-2651: The “Fire Hole Small” display is subscribed to the same
detection topic as “Fire Hole Large,” so the small and large views duplicate the
large-hole data. Update the topic used by the Fire Hole Small entry in the rviz
config to the corresponding small-hole topic, following the pattern already used
by the Blood Hole Small/Large displays. Keep the Fire Hole Large entry on the
_large topic and verify the two Fire Hole displays reference distinct topics.
- Around line 730-741: The RViz gate mapping display entries are still using the
old object names and topics, so update the two display blocks in
control_config_talos.rviz for the Gate Shark/Gate Saw mappings to match the new
naming used elsewhere. In the relevant RViz entries, rename the display labels
to Gate Repair and Gate Rescue and change their Topic Value fields from the old
gate_shark/gate_saw mappings to the corresponding gate_repair/gate_rescue topics
so the configuration stays consistent with markers.yaml and the dummy-detections
data.

---

Nitpick comments:
In `@riptide_rviz/riptide_rviz/src/MissionPanel.cpp`:
- Around line 29-31: The focus setting on btSelect in MissionPanel is blocking
keyboard navigation by using Qt::NoFocus. Update the MissionPanel setup so the
QComboBox can still receive keyboard focus, and use a styling approach or a less
restrictive focus policy to suppress the visual focus highlight instead. Keep
the change localized to the btSelect configuration in MissionPanel.cpp.

In `@riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp`:
- Around line 115-116: The comment on logUiScale has a typo: “JLog” should be
“Log”. Update the nearby comment in OverlayDisplay.cpp so it correctly says “Log
info about the ui scaling,” keeping the function name logUiScale unchanged.
- Around line 266-267: The OverlayDisplay::drawText path has an unused
QFontMetrics fm declaration left behind after removing the text_rect
calculation, which can trigger warnings or break builds with -Werror. Remove the
redundant fm variable from the block that creates only_wrapped_text, and keep
the wrapping/rendering logic in OverlayDisplay.cpp using only the symbols that
are still needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9f9c43fc-f061-48a7-aa0d-7f9fea5fc22b

📥 Commits

Reviewing files that changed from the base of the PR and between 1c1fe45 and bc9df4d.

⛔ Files ignored due to path filters (42)
  • riptide_meshes/meshes/bin/Task03_DropBRUVS.png is excluded by !**/*.png
  • riptide_meshes/meshes/bin/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/bin_magnet/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/bin_vinyl/Task3_Blood_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/bin_vinyl/Task3_Fire_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/bin_vinyl/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/gate_repair/Task1_SurveyRepair_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/gate_repair/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/gate_rescue/Task1_SearchRescue_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/gate_rescue/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/octagon_buoy/Task5_Search_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/octagon_buoy/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/octagon_compass/Task5_Survey_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/octagon_compass/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/octagon_hammer_and_wrench/Task5_Repair_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/octagon_hammer_and_wrench/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/octagon_sos/Task5_Rescue_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/octagon_sos/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/reefshark/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/sawfish/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_bandage/Task5_BandAid_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/table_bandage/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_basket_helmet/Task5_RedCross_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/table_basket_helmet/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_basket_pink/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_basket_warning/Task5_Warning_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/table_basket_warning/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_basket_yellow/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_bottle_pink/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_bottle_yellow/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_nut_and_bolt/Task5_NutBolt_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/table_nut_and_bolt/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_pill/Task5_Pill_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/table_pill/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_plug/Task5_Electric_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/table_plug/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_spoon_pink/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/table_spoon_yellow/model.dae is excluded by !**/*.dae
  • riptide_meshes/meshes/torpedo/Task04_Tagging_01.png is excluded by !**/*.png
  • riptide_meshes/meshes/torpedo/Task4_ver1_Fixed.png is excluded by !**/*.png
  • riptide_meshes/meshes/torpedo/model.dae is excluded by !**/*.dae
📒 Files selected for processing (11)
  • riptide_rviz/control_config_talos.rviz
  • riptide_rviz/riptide_rviz/config/markers.yaml
  • riptide_rviz/riptide_rviz/include/riptide_rviz/ControlPanel.hpp
  • riptide_rviz/riptide_rviz/include/riptide_rviz/MappingPanel.hpp
  • riptide_rviz/riptide_rviz/python/MarkerPublisher.py
  • riptide_rviz/riptide_rviz/src/ControlPanel.cpp
  • riptide_rviz/riptide_rviz/src/MappingPanel.cpp
  • riptide_rviz/riptide_rviz/src/MappingPanel.ui
  • riptide_rviz/riptide_rviz/src/MissionPanel.cpp
  • riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp
  • riptide_rviz/riptide_rviz/src/ParamPanel.cpp

Comment on lines +302 to 324

ghostBaseLinkPose = Pose()
ghostBaseLinkPose.position.x = ghost.pose.position.x
ghostBaseLinkPose.position.y = ghost.pose.position.y
ghostBaseLinkPose.position.z = ghost.pose.position.z
ghostBaseLinkPose.orientation.w = ghost.pose.orientation.w
ghostBaseLinkPose.orientation.x = ghost.pose.orientation.x
ghostBaseLinkPose.orientation.y = ghost.pose.orientation.y
ghostBaseLinkPose.orientation.z = ghost.pose.orientation.z

# Rotate the base_link offset vector from the robot frame
# into the world frame using the robot’s orientation.
q = [ghost.pose.orientation.w, ghost.pose.orientation.x, ghost.pose.orientation.y, ghost.pose.orientation.z]
v = [float(self.baseLinkOffset[0]), float(self.baseLinkOffset[1]), float(self.baseLinkOffset[2])]
v_as_quat = [0.0, v[0], v[1], v[2]]
q_conj = [q[0], -q[1], -q[2], -q[3]]
v_world = qmult(qmult(q, v_as_quat), q_conj)

# translates the ghost pose so the base_link is correctly positioned relative to origin
ghost.pose.position.x = ghost.pose.position.x - v_world[1]
ghost.pose.position.y = ghost.pose.position.y - v_world[2]
ghost.pose.position.z = ghost.pose.position.z - v_world[3]
array.markers.append(ghost)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm that assigning a message sub-pose does not deep-copy (mutation propagates back to source).
python - <<'PY'
try:
    from nav_msgs.msg import Odometry
    from visualization_msgs.msg import Marker
    o = Odometry()
    m = Marker()
    m.pose = o.pose.pose          # same assignment pattern as MarkerPublisher line 278
    m.pose.position.x = 5.0
    print("source mutated:", o.pose.pose.position.x == 5.0)
except Exception as e:
    print("env unavailable:", e)
PY

Repository: osu-uwrt/riptide_gui

Length of output: 202


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the target file and inspect the relevant section with line numbers.
git ls-files 'riptide_rviz/riptide_rviz/python/MarkerPublisher.py'
wc -l riptide_rviz/riptide_rviz/python/MarkerPublisher.py
sed -n '250,340p' riptide_rviz/riptide_rviz/python/MarkerPublisher.py

# Find related usages of latestOdom/latestSetpt and pose assignment patterns.
rg -n "latestOdom|latestSetpt|ghost\.pose|baseLinkOffset|ghostBaseLinkPose" riptide_rviz/riptide_rviz/python/MarkerPublisher.py

Repository: osu-uwrt/riptide_gui

Length of output: 7357


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('riptide_rviz/riptide_rviz/python/MarkerPublisher.py')
text = p.read_text()
for needle in [
    'ghost.pose = self.latestOdom.pose.pose',
    'ghost.pose = self.latestSetpt',
    'ghostBaseLinkPose = Pose()',
    'ghost.pose.position.x = ghost.pose.position.x - v_world[1]',
]:
    print(needle, '=>', needle in text)
PY

Repository: osu-uwrt/riptide_gui

Length of output: 345


🌐 Web query:

ROS 2 Python generated message field assignment stores a reference not a deep copy rosidl_generator_py message semantics

💡 Result:

In ROS 2 Python, message field assignment directly via class properties does not perform a deep copy; it stores a reference to the assigned object [1][2][3]. The generated Python code for ROS 2 messages uses standard Python property setters [1][2][3]. These setters enforce type constraints (such as verifying that a provided value matches the expected ROS message type) [1][2][3], but they do not internally clone or deep-copy the object being assigned [2][3]. Consequently, if you assign a mutable object (like a list or a nested message) to a field, modifying that original object elsewhere in your code will also affect the data stored inside the ROS 2 message [2][3]. Regarding helper utilities: - The common utility function set_message_fields, located in the rosidl_runtime_py package, is frequently used to populate message fields from dictionaries [4]. Historically, this function has been noted for modifying input dictionaries or objects during the population process [5][6]. - Recent updates (e.g., Pull Request #34 in rosidl_runtime_py) have addressed safety concerns by implementing deepcopy operations within set_message_fields to prevent unintended side effects on user-provided input data [5][6]. In summary, direct assignment to a message attribute is a reference assignment, and developers should be mindful of mutability when handling nested messages or arrays [1][2]. When using utility functions like set_message_fields, verify the version and behavior of your environment regarding deep copying to ensure data integrity [5][6].

Citations:


Avoid mutating the aliased pose in place. ghost.pose points at self.latestOdom.pose.pose / self.latestSetpt, so subtracting v_world here also changes the stored message. That makes the offset accumulate on subsequent timer ticks and drifts both the marker and the published ghost/base_link transform. Assign a fresh Pose/Point before applying the offset.

🧰 Tools
🪛 Ruff (0.15.20)

[warning] 313-313: Comment contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF003)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@riptide_rviz/riptide_rviz/python/MarkerPublisher.py` around lines 302 - 324,
Avoid mutating the aliased pose in place in the marker publishing path: in the
logic around ghost pose handling, `ghost.pose` is shared with
`self.latestOdom.pose.pose` / `self.latestSetpt`, so subtracting the rotated
base-link offset directly changes the stored source message and causes repeated
drift on later ticks. Update `MarkerPublisher` so it copies the pose into a
fresh `Pose`/`Point` object before applying the `v_world` offset, and then
append that independent marker pose instead of modifying the original.

Source: Linters/SAST tools

Comment on lines +102 to +113
// For high dpi displays
static float getUiScaleFactor()
{
QScreen* screen = QGuiApplication::primaryScreen();
if (!screen) return 1.0f;

const float dpr = static_cast<float>(screen->devicePixelRatio());
const float dpi = static_cast<float>(screen->logicalDotsPerInch() / 96.0);

const float s = std::max(dpr, dpi);
return std::max(1.0f, s);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Qt QScreen devicePixelRatio vs logicalDotsPerInch relationship for HiDPI scaling on X11/Wayland/Windows

💡 Result:

In Qt, logicalDotsPerInch and devicePixelRatio serve distinct purposes in the framework's HiDPI scaling architecture [1][2][3]. Relationship and Definitions Qt operates on a coordinate system of device-independent pixels (DIPs) [4][3]. These are mapped to physical screen pixels using a scale factor, known as the device pixel ratio (DPR) [4][3]. - devicePixelRatio (QScreen::devicePixelRatio or QWindow::devicePixelRatio): This is the effective scale factor representing the ratio between physical screen pixels and device-independent pixels [1][5][3]. It is often a product of the native OS scale factor (provided by the platform) and any Qt-specific scale factor (e.g., set via QT_SCALE_FACTOR) [2][3][6]. - logicalDotsPerInch: This value is used primarily to convert font sizes and user interface element dimensions (expressed in points or other logical units) into device-independent pixels [1][5]. It is often derived from user-settable desktop environment settings [1]. Key Interactions Qt calculates the necessary devicePixelRatio by comparing the target display's logical DPI to a reference "base" DPI (typically 96 on X11) [2][3]. When an OS reports a scale factor via DPI (e.g., 144 DPI), Qt translates this into a devicePixelRatio [2][3]. Platform-Specific Behavior - X11: Often provides only global logical DPI or per-screen physical DPI [2][3]. Because neither is a direct native scale factor, HiDPI configuration on X11 is frequently more complex than on other platforms [2][3]. QT_USE_PHYSICAL_DPI can be used to force Qt to use physical DPI if logical DPI is unavailable or incorrect [2][3]. - Wayland/Windows: These platforms generally provide native scaling information that Qt integrates directly into its devicePixelRatio calculation [3][6]. On Wayland, QWindow::devicePixelRatio may incorporate fractional scaling, which may differ from QScreen::devicePixelRatio depending on window-specific surface resolution settings [1][5]. Best Practices - Prefer QWindow::devicePixelRatio over QScreen::devicePixelRatio when a window instance is available [1][5]. QWindow::devicePixelRatio accurately tracks the DPR as the window moves between displays with different properties [2][3]. - logicalDotsPerInch is appropriate for UI layout and font scaling logic, whereas devicePixelRatio is intended for low-level drawing (e.g., OpenGL) and mapping coordinate systems to physical buffers [2][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== File outline ==\n'
ast-grep outline riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp --view expanded || true

printf '\n== Relevant excerpt ==\n'
sed -n '1,220p' riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp | cat -n

printf '\n== Search for getUiScaleFactor usages and screen/window APIs ==\n'
rg -n "getUiScaleFactor|primaryScreen|screen\(|windowHandle\(|QScreen|devicePixelRatio|logicalDotsPerInch" riptide_rviz/riptide_rviz/src riptide_rviz/riptide_rviz/include || true

Repository: osu-uwrt/riptide_gui

Length of output: 11723


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Call sites around getUiScaleFactor ==\n'
sed -n '330,400p' riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp | cat -n

printf '\n== OverlayDisplay declaration ==\n'
ast-grep outline riptide_rviz/riptide_rviz/include/riptide_rviz/OverlayDisplay.hpp --view expanded || true
sed -n '1,260p' riptide_rviz/riptide_rviz/include/riptide_rviz/OverlayDisplay.hpp | cat -n

printf '\n== Search for window/screen access in overlay-related code ==\n'
rg -n "windowHandle\(|screen\(\)|QWidget|QWindow|QGuiApplication::primaryScreen|QScreen" riptide_rviz/riptide_rviz/include riptide_rviz/riptide_rviz/src || true

Repository: osu-uwrt/riptide_gui

Length of output: 17239


Scale from the RViz render window, not the primary screen. primaryScreen() can mis-size the overlay on multi-monitor setups, and max(devicePixelRatio(), logicalDotsPerInch()/96) can over-scale on platforms where Qt already folds DPI scaling into DPR. Use the screen/window that owns the RViz surface, and keep DPR and logical DPI separate unless there’s a platform-specific reason to combine them.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp` around lines 102 - 113, The
UI scaling logic in getUiScaleFactor() is using QGuiApplication::primaryScreen()
and combining devicePixelRatio with logicalDotsPerInch(), which can mis-scale
overlays on multi-monitor setups. Update the scale source to use the RViz render
window’s owning screen/window instead of the primary screen, and adjust the
calculation so DPR and logical DPI are not blindly merged unless there’s a
platform-specific need. Keep the change localized to getUiScaleFactor() in
OverlayDisplay.cpp and preserve the existing high-DPI fallback behavior.

Comment on lines 228 to 234
if (config.font_size_ != 0) {
// QFont font = painter.font();
QFont font(config.font_name_.length() > 0 ? config.font_name_.c_str() : "Liberation Sans");
font.setPointSize(config.font_size_);
font.setPixelSize(std::max(config.font_size_, 1));
font.setBold(true);
painter.setFont(font);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Font pixel size is not scaled while texture dimensions are — inconsistent DPI scaling.

updateWidth()/updateHeight() multiply the configured width/height by getUiScaleFactor(), but paintText() still uses config.font_size_ unscaled via setPixelSize(). Since the overlay canvas grows on high-DPI displays but the font size doesn't, text will render visually smaller relative to the overlay/anchors than before this change, undermining the intent of the DPI-scaling feature.

💡 Proposed fix: scale font size consistently with texture dimensions
         if (config.font_size_ != 0) {
             // QFont font = painter.font();
             QFont font(config.font_name_.length() > 0 ? config.font_name_.c_str() : "Liberation Sans");
-            font.setPixelSize(std::max(config.font_size_, 1));
+            font.setPixelSize(std::max(static_cast<int>(std::lround(config.font_size_ * getUiScaleFactor())), 1));
             font.setBold(true);
             painter.setFont(font);
         }

Also applies to: 368-378

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@riptide_rviz/riptide_rviz/src/OverlayDisplay.cpp` around lines 228 - 234, The
font sizing in OverlayDisplay::paintText is not using the same DPI scaling as
the overlay dimensions, so text stays visually smaller on high-DPI displays.
Update the font setup in paintText to apply getUiScaleFactor() consistently when
calling QFont::setPixelSize, using the same scale logic already used by
updateWidth() and updateHeight(), and make sure the other paintText occurrence
uses the same adjusted sizing path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants