-
Notifications
You must be signed in to change notification settings - Fork 0
Merge HSV Refactoring 2 into Prequal #112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
* Robot agnostic support * Robot agnostic support * Add status timeout * Copy topic on click * Deprecate call-service-panel and subscribe-topic-panel * Update foxglove/extensions/system-status-panel/src/SystemStatusPanel.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add buttons to set ROBOT_NAME * Add toasts for copy action * Disable buttons when callService unavailable * Initial attempt at automatic deployement * Add test branch * Remove variable check * Only publish on pushes to main * Rename * Update docs * Update docs
…but got rid of it from setup.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR refactors the HSV vision pipeline to add reusable HSV filter nodes (including a new hsv_lane_marker node) and wires them into the ROS 2 cv package, while also updating Foxglove extensions (system/sensor status, discrete servos, publish panel) and adding CI for publishing Foxglove extensions.
Changes:
- Introduces dedicated HSV filter nodes for the lane marker and bin detections, refactors the base
HSVFilterto support multiple publishers, and adjusts package entry points and launches accordingly. - Enhances Foxglove extensions with a shared robot-name helper (including a clickable
NoRobotNameAlert), more robust system/sensor status panels, discrete servo controls keyed by robot, and documentation updates. - Adds a GitHub Actions workflow plus helper scripts for building and publishing all Foxglove extensions from CI.
Reviewed changes
Copilot reviewed 29 out of 36 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
sonar_plot.png |
Updates/introduces a PNG asset, likely for visualization; no code logic impact. |
onboard/src/cv/setup.py |
Simplifies data_files formatting and updates console_scripts to remove lane_marker_detector and register new HSV-based executables (hsv_lane_marker, hsv_red_bin, hsv_pink_bin_front, hsv_pink_bin_bottom). |
onboard/src/cv/launch/lane_marker_detector.xml |
Normalizes whitespace/line endings while retaining a launch description that still refers to the now-removed lane_marker_detector executable (this will no longer start successfully). |
onboard/src/cv/launch/hsv_lane_marker.xml |
Adds a ROS 2 launch file to start the new hsv_lane_marker node from the cv package. |
onboard/src/cv/cv/utils.py |
Narrows the type hint of calculate_relative_pose’s bbox_bounds to a tuple, aligning it with how bounding boxes are constructed elsewhere. |
onboard/src/cv/cv/hsv_filters/hsv_red_bin.py |
Adds a HSVRedBin node specialization over HSVFilter with red bin HSV ranges and simple morphology, but its filter() currently returns a single contour instead of the list the base class expects. |
onboard/src/cv/cv/hsv_filters/hsv_pink_bin_front.py |
Adds a HSVPinkBinFront node that groups contours by distance and selects a rightmost large contour; imports utils via a non-package path and returns a single contour/None instead of a contour list, which is incompatible with HSVFilter. |
onboard/src/cv/cv/hsv_filters/hsv_pink_bin_bottom.py |
Adds a HSVPinkBinBottom node for bottom camera pink/yellow bins with contour grouping and selection; suffers from the same utils import issue and filter() return-type mismatch as the front variant. |
onboard/src/cv/cv/hsv_filters/hsv_lane_marker.py |
Introduces HSVLaneMarker, an HSV-based lane marker detector that subclasses HSVFilter, but its process_contours signature does not match the base class call site, misuses a Point when populating distance messages, and publishes lane marker topics under /cv/bottom_usb/... while task-planning still expects /cv/bottom/.... |
onboard/src/cv/cv/hsv_filters/hsv_filter_torpedos.py |
Reformats the mask_ranges initialization for torpedo HSV filtering without changing behavior. |
onboard/src/cv/cv/hsv_filters/__init__.py |
Ensures hsv_filters is a Python package (content not shown, likely an empty marker); required for cv.hsv_filters.* imports. |
onboard/src/cv/cv/hsv_filter.py |
Refactors the base HSV filter into an abstract HSVFilter with configurable publisher sets, abstract filter/morphology, a factored-out process_contours, and more robust image handling; existing subclasses must now conform to its expectations (list-of-contours, process signature, width/height semantics). |
onboard/src/cv/cv/config.py |
Removes unused BlueRect HSV constants, leaving other color configuration (e.g., PathMarker, LaneMarker) unchanged. |
foxglove/shared/theme/src/useTheme.ts |
Extends the theme to set default MuiSnackbar anchor position, auto-hide duration, and absolute positioning for consistent snackbars across panels. |
foxglove/shared/robot-name/src/NoRobotNameAlert.tsx |
Changes NoRobotNameAlert to accept a PanelExtensionContext and exposes clickable robot-name links that call context.setVariable("ROBOT_NAME", ...) when no robot name is set. |
foxglove/shared/robot-name/README.md |
Updates the example usage of NoRobotNameAlert to pass the Foxglove context prop, matching the new component signature. |
foxglove/foxglove.py |
Extends the publish CLI and function with a --github-action flag that appends -prod to the version tag to avoid collisions; wires the new flag into argument parsing and the publish dispatcher. |
foxglove/extensions/toggle-joystick-panel/README.md |
Updates usage instructions to use ros2 launch controls controls.xml instead of the ROS 1 roslaunch invocation. |
foxglove/extensions/system-status-panel/src/SystemStatusPanel.tsx |
Refactors the panel to use the shared robot-name helpers, per-robot status configurations, topic last-seen time tracking, topic-down detection, tooltip improvements, and a snackbar that confirms when a topic name is copied to the clipboard. |
foxglove/extensions/subscribe-topic-panel/tsconfig.json |
Removes the TypeScript config for the now-deleted Subscribe Topic panel, reflecting its deprecation. |
foxglove/extensions/subscribe-topic-panel/src/index.ts |
Removes the extension entrypoint that registered the Jazzy Subscribe Topic panel. |
foxglove/extensions/subscribe-topic-panel/src/SubscribeTopicPanel.tsx |
Deletes the implementation of the generic subscribe-topic example panel. |
foxglove/extensions/subscribe-topic-panel/package.json |
Removes the NPM package definition for the Jazzy Subscribe Topic panel. |
foxglove/extensions/subscribe-topic-panel/README.md |
Deletes the README for the deprecated Subscribe Topic panel. |
foxglove/extensions/sensors-status-panel/src/SensorsStatusPanel.tsx |
Integrates the new robot-name alert, adds click-to-copy-topic behavior with snackbar feedback, and tweaks tooltip placement while preserving the sensor up/down logic based on message recency. |
foxglove/extensions/publish-topic-panel/README.md |
Expands the README to explain advantages over the built-in Foxglove Publish panel and notes support for custom schemas and continuous publishing (contains a small spelling issue: “build-in” → “built-in”). |
foxglove/extensions/discrete-servos-panel/src/DiscreteServosPanel.tsx |
Refactors the discrete servos panel to be robot-aware via useRobotName, splitting available servos by robot, adding the robot-name alert, handling renderDone, and disabling controls when services are unavailable. |
foxglove/extensions/call-service-panel/tsconfig.json |
Removes the TypeScript config for the Jazzy Call Service example panel. |
foxglove/extensions/call-service-panel/src/index.ts |
Deletes the extension entrypoint for the Call Service panel. |
foxglove/extensions/call-service-panel/src/CallServicePanel.tsx |
Removes the implementation of the generic Call Service example panel. |
foxglove/extensions/call-service-panel/package.json |
Deletes the NPM package for the Jazzy Call Service panel. |
foxglove/extensions/call-service-panel/README.md |
Removes the README for the Call Service panel. |
foxglove/README.md |
Documents the new --github-action flag for fox publish, removes references to the removed example panels, and slightly generalizes guidance on copying existing extensions. |
.github/workflows/publish-foxglove.sh |
Adds a small helper script that sources the ROS environment and runs foxglove.py publish --github-action inside the container. |
.github/workflows/publish-foxglove-extensions.yml |
Introduces a new GitHub Actions workflow that builds the Docker image, brings up the container, builds Foxglove dependencies, configures Foxglove authentication from a secret API key, and publishes all Foxglove extensions on pushes to main. |
.github/workflows/build-and-lint.yml |
Splits the combined “build and run” step into separate “Build Docker image” and “Run Docker container” steps while continuing to use docker-build.sh --github-action. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def process_contours(self, final_contours: list[np.ndarray], image: np.ndarray) -> None: | ||
| """Process lane marker contour.""" | ||
| if not final_contours: | ||
| self.get_logger().error('No contours found?') |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if not final_contours: logs an error but then continues, so when final_contours is empty the subsequent np.vstack(final_contours) will raise a ValueError (need at least one array to concatenate). To avoid crashing the node, this branch should return early (or otherwise short-circuit) when no contours are available.
| self.get_logger().error('No contours found?') | |
| self.get_logger().error('No contours found?') | |
| return |
| self.get_logger().error(f'Failed to publish processed image: {e}') | ||
|
|
||
| def filter(self, contours: list) -> list: | ||
| """Pick the largest contour onguly.""" |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This docstring appears to have a typo: "onguly" should be "only". Please correct the spelling to avoid confusion for future readers.
| """Pick the largest contour onguly.""" | |
| """Pick the largest contour only.""" |
|
|
||
| def create_additional_pubs_subs_vars(self) -> None: | ||
| """Additional publishers and subscribers specific to this class.""" | ||
| self.angle_pubs = [self.create_publisher(Float64, '/cv/bottom_usb/lane_marker/angle', 10)] |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This publisher (and the inherited bounding_box_pubs/distance_pubs) use the /cv/bottom_usb/lane_marker/... namespace, but the task-planning CV interface still subscribes to /cv/bottom/lane_marker/... topics (see onboard/src/task_planning/task_planning/interface/cv.py:70-97). Combined with the removal of the lane_marker_detector console script, this leaves CVObjectType.LANE_MARKER subscribers with no data source; please either keep publishing on the existing /cv/bottom/... topics or update the consumers to match the new topic names in the same PR.
| self.angle_pubs = [self.create_publisher(Float64, '/cv/bottom_usb/lane_marker/angle', 10)] | |
| self.angle_pubs = [self.create_publisher(Float64, '/cv/bottom/lane_marker/angle', 10)] |
| <launch> | ||
| <node name="lane_marker_detector" pkg="cv" exec="lane_marker_detector" output="screen"/> |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This launch file still references the lane_marker_detector executable, but the corresponding console script ('lane_marker_detector = cv.lane_marker_detector:main') has been removed from onboard/src/cv/setup.py. As a result, running this launch file will fail to start the node; please either restore the console script entry, update this launch file to use the new hsv_lane_marker executable, or remove the obsolete launch file.
| @@ -1,5 +1,7 @@ | |||
| # Publish Topic Panel | |||
| This is an example panel to publish topics. Base a new extension off of this panel if it requires publishing topics. | |||
| This panel allows you to publish topics. Compared to the build-in Foxglove Publish panel, this custom panel allows for the following: | |||
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this README sentence, "build-in" should be "built-in" ("Compared to the built-in Foxglove Publish panel, ..."). Please fix the spelling to improve documentation quality.
| This panel allows you to publish topics. Compared to the build-in Foxglove Publish panel, this custom panel allows for the following: | |
| This panel allows you to publish topics. Compared to the built-in Foxglove Publish panel, this custom panel allows for the following: |
| def process_contours(self, final_contours: list[np.ndarray], image: np.ndarray) -> None: | ||
| """Process lane marker contour.""" |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This override of process_contours has a different signature than the base HSVFilter.process_contours (which expects (self, final_contours, image, bbox_img)), but image_callback still calls self.process_contours(final_contours, image, bbox_img). At runtime this will raise a TypeError (takes 3 positional arguments but 4 were given) and prevent the lane marker node from publishing anything. Please either update this method to accept the same parameters as the base implementation (and handle bbox_img appropriately) or override image_callback so the call site matches this signature.
| def process_contours(self, final_contours: list[np.ndarray], image: np.ndarray) -> None: | |
| """Process lane marker contour.""" | |
| def process_contours(self, final_contours: list[np.ndarray], image: np.ndarray, bbox_img: np.ndarray | None) -> None: | |
| """Process lane marker contour. | |
| The bbox_img argument is accepted for compatibility with the base | |
| HSVFilter interface and is currently not used. | |
| """ |
|
|
||
| if distance is not None: | ||
| distance_msg = Point() | ||
| distance_msg.y = distance |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here distance is a geometry_msgs/Point (initialized above), but distance_msg.y = distance assigns the entire Point object into a field that expects a scalar float. In ROS 2 Python this will raise a type error at runtime; to preserve the existing semantics, assign a numeric component (e.g., distance.y) instead of the whole message.
| distance_msg.y = distance | |
| distance_msg.y = distance.y |
| self.contour_image_pubs.append(self.create_publisher(Image, f'{base}/contour_image', 10)) | ||
| self.distance_pubs.append(self.create_publisher(Point, f'{base}/distance', 10)) | ||
|
|
||
| self.create_additional_pubs_subs_vars() |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This call to HSVFilter.create_additional_pubs_subs_vars in an initialization method is overridden by HSVLaneMarker.create_additional_pubs_subs_vars.
| self.create_additional_pubs_subs_vars() | |
| HSVFilter.create_additional_pubs_subs_vars(self) |
| try: | ||
| rclpy.spin(hsv_filter) | ||
| except KeyboardInterrupt: | ||
| pass |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'except' clause does nothing but pass and there is no explanatory comment.
| pass | |
| hsv_filter.get_logger().info('Shutting down HSVLaneMarker due to KeyboardInterrupt') |
|
The single failure in build and lint was in IVC, which is a known issue. |
Merging HSV refactoring 2 to allow us to use hsv_lane_marker.py for prequals.