Skip to content

feat: hangar_sim, add beluga_amcl localization with hardcoded initial…#605

Draft
bkanator wants to merge 1 commit into
mainfrom
add_beluga_amcl
Draft

feat: hangar_sim, add beluga_amcl localization with hardcoded initial…#605
bkanator wants to merge 1 commit into
mainfrom
add_beluga_amcl

Conversation

@bkanator

@bkanator bkanator commented Apr 30, 2026

Copy link
Copy Markdown

Closes PickNikRobotics/moveit_pro#18065

Adds beluga_amcl localization to hangar_sim and makes the navigation Objectives recover cleanly between runs.

What

  • Enables beluga_amcl as the AMCL localizer when slam:=False (default localization:=True), replacing the static identity map → odom TF. map_server + beluga_amcl + lifecycle_manager load into the existing nav2_container; an initial pose is published 3 s after launch so the filter seeds at the sim spawn without a manual estimate.
  • Reset Localization subtree at the start of the clicked-point nav Objectives: re-seeds beluga at the robot's current odom pose via /initialpose, then clears the global/local costmaps.
  • Wraps the nav body so controllers are always restored to joint_trajectory_controller on failure — fixes "objective fails → can't run anything until restart."

Why

The old setup had no real localization (a static identity TF stood in for map → odom). beluga estimates the pose from laser scans; the reset + controller-restore make failed runs recoverable in place.

Depends on

PickNikRobotics/moveit_pro#19710 — adds the SetInitialPose and ClearCostmap Behaviors these Objectives use. CI here fails until that merges.

Release notes

Enhancement: Added beluga_amcl localization to hangar_sim, replacing the static map → odom identity TF with laser-scan-based localization, with automatic localization + costmap reset and controller recovery on each navigation run.

Claude agent checks

  • code-reviewer
  • test-runner
  • platform-architect-bot

@bkanator bkanator force-pushed the add_beluga_amcl branch from af4465b to 23bb875 Compare May 5, 2026 12:12
@bkanator bkanator marked this pull request as draft May 5, 2026 14:17
@bkanator bkanator marked this pull request as draft May 5, 2026 14:17
@bkanator bkanator force-pushed the add_beluga_amcl branch 2 times, most recently from 9a9d7a0 to 308ed11 Compare May 12, 2026 17:07
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aed10653-dc26-4270-8bbe-173334e98b9d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR enables map-based localization using beluga_amcl in the simulation environment. It refactors localization_launch.py to composable-only mode with runtime map validation, conditionally loads AMCL and map server components, publishes initial pose with a 3-second delay, integrates the feature into the parent launch with proper argument propagation, and activates AMCL parameters while adding the required runtime dependency.

Changes

Localization feature enablement

Layer / File(s) Summary
Localization launch refactoring
src/hangar_sim/launch/sim/localization_launch.py
Removed non-composable execution path and simplified to always use composition. Added OpaqueFunction for runtime map file validation (when localization enabled). Conditional composed node loading: map_server + beluga_amcl + lifecycle manager when enabled, map server only when disabled. New delayed /initialpose publication via TimerAction + ExecuteProcess (3-second delay, gated on localization). Updated imports and rewrote LaunchDescription assembly to directly declare localization argument and add new action objects.
Parent launch integration
src/hangar_sim/launch/sim/robot_drivers_to_persist_sim.launch.py
Added localization LaunchConfiguration variable and declared new localization argument (default True). Passed localization config through to localization launch via launch_arguments. Updated static_tf_map_to_odom condition to only start when both slam and localization are disabled. Registered the localization argument in LaunchDescription.
AMCL configuration and dependency
src/hangar_sim/params/nav2_params.yaml, src/hangar_sim/package.xml
Enabled previously commented-out AMCL parameters section as active configuration. Updated integration fields: base_frame_idridgeback_base_link, robot_model_typebeluga_amcl::DifferentialMotionModel, scan_topic/scan_front_filtered. Added beluga_amcl as new runtime dependency.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Human Review Check ✅ Passed PR modifies only hangar_sim simulation launch and parameter files; no auth, secrets, CI/CD, infrastructure, or public API changes detected.
Description check ✅ Passed The pull request description clearly explains the addition of beluga_amcl localization, the motivation (replacing static identity TF), implementation details (loading into nav2_container with lifecycle manager), and the related changes (reset localization, controller restoration). The description is directly related to the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@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: 2

Caution

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

⚠️ Outside diff range comments (1)
src/hangar_sim/launch/sim/robot_drivers_to_persist_sim.launch.py (1)

329-337: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix duplicate condition keyword in static_tf_map_to_odom Node call (parse-time failure).

static_tf_map_to_odom = Node(...) passes condition= twice (lines 329-337), which prevents the launch file from compiling/executing. Remove the second condition.

Suggested fix
     static_tf_map_to_odom = Node(
         condition=IfCondition(
             PythonExpression(["not ", slam, " and not ", localization])
         ),
         package="tf2_ros",
         executable="static_transform_publisher",
         name="static_tf_map_to_odom",
         output="log",
         arguments=["0.0", "0.0", "0.0", "0.0", "0.0", "0.0", "map", "odom"],
-        condition=IfCondition(PythonExpression(["not ", slam])),
     )
🤖 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 `@src/hangar_sim/launch/sim/robot_drivers_to_persist_sim.launch.py` around
lines 329 - 337, The Node call that creates static_tf_map_to_odom passes the
condition= keyword twice causing a parse error; edit the Node(...) for
static_tf_map_to_odom to remove the duplicate condition argument (keep the
intended condition IfCondition(PythonExpression(["not ", slam, " and not ",
localization])) and delete the later
condition=IfCondition(PythonExpression(["not ", slam]))). Ensure only one
condition kwarg exists on the static_tf_map_to_odom Node to restore valid launch
file syntax.
🤖 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 `@src/hangar_sim/launch/sim/localization_launch.py`:
- Line 60: Remove the unused LaunchConfiguration assignment by deleting the
log_level = LaunchConfiguration("log_level") line (remove the symbol log_level
and its LaunchConfiguration call) so the unused variable no longer triggers
F841; ensure no other references to log_level remain and run lint to confirm the
warning is resolved.
- Around line 82-83: The gate compares
context.perform_substitution(localization) to the exact string "True", which
fails for "true"/" TRUE"/etc.; normalize the substituted localization value
before comparing (e.g., call .strip().lower() on the result) so the check uses a
boolean-safe comparison in the if statement that currently references
localization; update that condition in localization_launch.py to compare the
normalized string to "true".

---

Outside diff comments:
In `@src/hangar_sim/launch/sim/robot_drivers_to_persist_sim.launch.py`:
- Around line 329-337: The Node call that creates static_tf_map_to_odom passes
the condition= keyword twice causing a parse error; edit the Node(...) for
static_tf_map_to_odom to remove the duplicate condition argument (keep the
intended condition IfCondition(PythonExpression(["not ", slam, " and not ",
localization])) and delete the later
condition=IfCondition(PythonExpression(["not ", slam]))). Ensure only one
condition kwarg exists on the static_tf_map_to_odom Node to restore valid launch
file syntax.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 00862f77-0187-4d32-8292-dec8e39708d2

📥 Commits

Reviewing files that changed from the base of the PR and between 87f07b8 and b18a6a3.

📒 Files selected for processing (4)
  • src/hangar_sim/launch/sim/localization_launch.py
  • src/hangar_sim/launch/sim/robot_drivers_to_persist_sim.launch.py
  • src/hangar_sim/package.xml
  • src/hangar_sim/params/nav2_params.yaml

container_name = LaunchConfiguration("container_name")
container_name_full = (namespace, "/", container_name)
use_respawn = LaunchConfiguration("use_respawn")
log_level = LaunchConfiguration("log_level")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove the unused log_level LaunchConfiguration assignment.

Line 60 is assigned but never used, matching the reported F841 and likely failing lint CI.

Suggested fix
-    log_level = LaunchConfiguration("log_level")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
log_level = LaunchConfiguration("log_level")
🧰 Tools
🪛 Flake8 (7.3.0)

[error] 60-60: local variable 'log_level' is assigned to but never used

(F841)

🤖 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 `@src/hangar_sim/launch/sim/localization_launch.py` at line 60, Remove the
unused LaunchConfiguration assignment by deleting the log_level =
LaunchConfiguration("log_level") line (remove the symbol log_level and its
LaunchConfiguration call) so the unused variable no longer triggers F841; ensure
no other references to log_level remain and run lint to confirm the warning is
resolved.

Comment on lines +82 to +83
if context.perform_substitution(localization) != "True":
return []

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Normalize the localization value before map-check gating.

Line 82 does an exact "True" comparison, so localization:=true skips validation while localization can still run. Make the gate boolean-safe.

Suggested fix
     def check_map_exists(context):
-        if context.perform_substitution(localization) != "True":
+        localization_enabled = (
+            context.perform_substitution(localization).strip().lower()
+            in ("true", "1", "yes", "on")
+        )
+        if not localization_enabled:
             return []
🤖 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 `@src/hangar_sim/launch/sim/localization_launch.py` around lines 82 - 83, The
gate compares context.perform_substitution(localization) to the exact string
"True", which fails for "true"/" TRUE"/etc.; normalize the substituted
localization value before comparing (e.g., call .strip().lower() on the result)
so the check uses a boolean-safe comparison in the if statement that currently
references localization; update that condition in localization_launch.py to
compare the normalized string to "true".

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

MoveIt Pro Example WS - Objectives Integration Test Report

@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown

MoveIt Pro Example WS - Objectives Integration Test Report

@bkanator

bkanator commented Jun 9, 2026

Copy link
Copy Markdown
Author

here are initial videos with beluga integrated with ground truth odom but not tuning.

first is a successful run, and the second is showing failure with getting near the plane.

particle_first-2026-06-09_09.52.29.mp4
particle_fail-2026-06-09_09.47.02.mp4

@bkanator

Copy link
Copy Markdown
Author

Todo: fix reset of particles after failure, tune resampling weights.

@github-actions

Copy link
Copy Markdown

MoveIt Pro Example WS - Objectives Integration Test Report

@github-actions

Copy link
Copy Markdown

MoveIt Pro Example WS - Objectives Integration Test Report

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.

1 participant