Skip to content

Start Beast motion enabled and interlock on detection - #155

Merged
Coldaine merged 1 commit into
mainfrom
fix/beast-normal-motion-startup
Aug 3, 2026
Merged

Start Beast motion enabled and interlock on detection#155
Coldaine merged 1 commit into
mainfrom
fix/beast-normal-motion-startup

Conversation

@Coldaine

@Coldaine Coldaine commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

What changed

Normal BEAST bringup now starts with allow_motion:=true. The Ethernet/charging safety monitor remains enabled and requests allow_motion=false only after it observes an active physical interlock.

Why

Default-disarmed startup was project policy, not a ROS 2 requirement, and conflicts with the requested normal operating behavior. The command-timeout watchdog is unchanged.

Validation

  • 66 passed: focused bringup safety, interlock, and command-spine tests
  • git diff --check
  • systemd syntax will be verified on BEAST before the service is switched

Summary

Normal BEAST bringup now starts with allow_motion:=true.

  • Ethernet and charging interlocks still disable motion through /ugv/set_allow_motion.
  • The command-timeout watchdog remains unchanged.
  • Launch defaults, systemd configuration, safety monitor behavior, tests, and BEAST documentation now reflect motion-enabled startup.
  • Safety documentation clarifies unknown Ethernet status and absent charging topics.

Validation

  • 66 focused bringup, safety, interlock, and command-spine tests passed.
  • git diff --check passed.
  • systemd syntax verification is planned on BEAST before service activation.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

BEAST ROS startup now enables motion by default. Ethernet and charging interlocks can disable motion through the safety monitor. Launch configurations, deployment settings, documentation, logging, and safety tests now reflect this behavior.

Changes

BEAST motion defaults

Layer / File(s) Summary
Motion-enabled launch wiring
robot/beast/ros2_ws/deploy/systemd/beast-ros-base.service, robot/beast/ros2_ws/src/ugv_main/ugv_bringup/..., robot/beast/ros2_ws/src/ugv_main/ugv_nav/..., robot/beast/ros2_ws/src/ugv_main/ugv_slam/...
Systemd and ROS launch configurations now enable motion by default.
Interlock safety behavior
robot/beast/ros2_ws/deploy/systemd/ugv.env.example, robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/..., docs/beast-ops.md
Documentation and startup logging now describe motion-enabled operation with Ethernet and charging interlocks disabling motion. Safety-state comments clarify carrier and charging behavior.
Motion default validation
robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/...
Safety tests now expect enabled motion defaults while retaining interlock and safety-monitor assertions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested labels: size:L

Poem

A rabbit sees the rover wake,
With motion ready for the trail.
If charging or Ethernet locks,
The safety monitor makes it fail-safe.
No secret re-arm through the veil.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains what changed, why, and validation, but it omits most required template sections. Add Branch Scope, PR Shape, Independent Review, Documentation, Superseded Docs/Cleanup, and Risk/Rollback sections with the required details.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: motion starts enabled and interlocks can disable it.
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 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/beast-normal-motion-startup

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.

@Coldaine
Coldaine marked this pull request as ready for review August 3, 2026 06:30
Copilot AI review requested due to automatic review settings August 3, 2026 06:30
@coderabbitai coderabbitai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Aug 3, 2026
@Coldaine
Coldaine merged commit 60fc95d into main Aug 3, 2026
7 of 8 checks passed
@Coldaine
Coldaine deleted the fix/beast-normal-motion-startup branch August 3, 2026 06:31

Copilot AI 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.

Pull request overview

Updates BEAST-01 ROS 2 bringup defaults to start with motion enabled (allow_motion:=true) while keeping the Ethernet/charging interlock monitor active so it can request disarm when an interlock is present, and aligns tests/docs/service config to the new default.

Changes:

  • Flip allow_motion default to true across bringup and related SLAM/Nav launch files.
  • Update ugv_bringup parameter default and systemd unit to launch motion-enabled.
  • Refresh safety monitor docs/tests to match the new “motion-enabled by default” behavior.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
robot/beast/ros2_ws/src/ugv_main/ugv_slam/launch/slam_toolbox.launch.py Default forwarded allow_motion to true for SLAM launch.
robot/beast/ros2_ws/src/ugv_main/ugv_nav/launch/nav.launch.py Default forwarded allow_motion to true for Nav launch.
robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_monitor.py Update monitor doc/log wording to match new motion-enabled startup behavior.
robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_logic.py Adjust interlock state/comment wording consistent with new defaults.
robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_twist_mux_spine.py Update guard-rail tests for allow_motion default-on.
robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_safety_monitor.py Update safety-monitor tests for bringup default-on.
robot/beast/ros2_ws/src/ugv_main/ugv_bringup/ugv_bringup/ugv_bringup.py Change allow_motion parameter default to true in bringup node.
robot/beast/ros2_ws/src/ugv_main/ugv_bringup/launch/bringup_lidar.launch.py Change launch default to true; update launch argument descriptions.
robot/beast/ros2_ws/deploy/systemd/ugv.env.example Update on-robot env example comments for motion-enabled startup.
robot/beast/ros2_ws/deploy/systemd/beast-ros-base.service Launch service with allow_motion:=true.
docs/beast-ops.md Update ops runbook to describe motion-enabled startup and interlock behavior.
Suppressed comments (2)

robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_monitor.py:109

  • This startup log line claims the monitor “disables only active locks”, but the logic also disarms on unknown/unreadable Ethernet carrier (fail-closed). Consider rewording to avoid implying it will never disarm on uncertainty/misconfiguration.
        self.get_logger().info(
            f'ugv_safety_monitor: iface={self._iface} path={self._carrier_path} '
            f'(client of {self._set_service_name}; disables only active locks)'
        )

robot/beast/ros2_ws/src/ugv_main/ugv_bringup/launch/bringup_lidar.launch.py:88

  • This description says the safety monitor “disables motion only when an interlock is observed”, but the monitor also disarms on unknown/unreadable Ethernet carrier (treating uncertainty as unsafe). The description should mention that fail-closed behavior.
    use_safety_monitor_arg = DeclareLaunchArgument(
        'use_safety_monitor', default_value='true',
        description=(
            'Start ugv_safety_monitor (ethernet/charging interlocks as a '
            'client of /ugv/set_allow_motion). It disables motion only when '
            'an interlock is observed.'
        )

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +12 to +14
Normal bringup starts motion-enabled. When Ethernet or charging is observed,
this monitor asks ugv_bringup to disable motion. It does not auto-arm when an
interlock later clears; ugv_bringup remains the sole motion authority.
Comment on lines 74 to 79
allow_motion_arg = DeclareLaunchArgument(
'allow_motion', default_value='false',
'allow_motion', default_value='true',
description=(
'Permit non-zero cmd_vel commands; keep false until physical '
'safety validation passes. Runtime flips go through '
'/ugv/set_allow_motion (ugv_bringup) — never default this true.'
'Permit non-zero cmd_vel commands by default. Active Ethernet or '
'charging interlocks may disable it through /ugv/set_allow_motion.'
)
Comment thread docs/beast-ops.md
Comment on lines +185 to +187
`beast-ros-base.service` is **active** from the RobotOverview workspace. It starts with
`use_lidar:=true`, `allow_motion:=true`; the active `ugv_safety_monitor` disables motion
only after detecting Ethernet or charging. Base driver, LD19 LiDAR, pan-tilt
Comment on lines 9 to +11
# LD19 USB serial — stable by-id symlink (Wave 0 verified: serial …5970075705 → ttyACM1).
# beast-ros-base launches with use_lidar:=true; keep allow_motion:=false until Set 1 re-gate.
# beast-ros-base launches motion-enabled. ugv_safety_monitor disables motion when it
# observes an active Ethernet or charging interlock.
Comment on lines 14 to 16
Environment=PYTHONUNBUFFERED=1
ExecStart=/bin/bash -lc 'source /opt/ros/humble/setup.bash && source /home/beast/beast/RobotOverview/robot/beast/ros2_ws/install/setup.bash && exec ros2 launch ugv_bringup bringup_lidar.launch.py use_lidar:=true use_rviz:=false allow_motion:=false'
ExecStart=/bin/bash -lc 'source /opt/ros/humble/setup.bash && source /home/beast/beast/RobotOverview/robot/beast/ros2_ws/install/setup.bash && exec ros2 launch ugv_bringup bringup_lidar.launch.py use_lidar:=true use_rviz:=false allow_motion:=true'
KillSignal=SIGINT
Comment on lines +963 to 965
assert "self.declare_parameter('allow_motion', True)" in source, (
'allow_motion must default on; the interlock monitor disables active locks'
)
Comment on lines 27 to 31
allow_motion_arg = DeclareLaunchArgument(
'allow_motion', default_value='false',
'allow_motion', default_value='true',
description=(
'Forwarded to bringup_lidar; keep false until Set 1 motion re-gate'
'Forwarded to bringup_lidar; active interlocks may disable motion'
),
Comment on lines 164 to 171
DeclareLaunchArgument(
'allow_motion',
default_value='false',
default_value='true',
description=(
'Forwarded to bringup_lidar; keep false until Set 1 motion re-gate. '
'Forwarded to bringup_lidar; active interlocks may disable motion. '
'Never stack this launch on a live beast-ros-base (second twist_mux) — '
'stop the service first.'
),

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

Caution

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

⚠️ Outside diff range comments (2)
robot/beast/ros2_ws/src/ugv_main/ugv_bringup/ugv_bringup/ugv_bringup.py (1)

113-136: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Always stop the base during initialization.

With allow_motion=True, Lines 135-136 no longer call send_stop_command(). The supplied docs/beast-ops.md states that the ESP32 latches the last non-zero command and has no lower-level failsafe. A service restart can therefore retain stale motion before the first command or interlock request. The watchdog does not cover this state because it is not armed until a non-zero command is accepted.

Send an explicit stop unconditionally after opening the controller.

Suggested startup safing change
-        if not self.allow_motion:
-            self.send_stop_command()
+        # Clear any velocity latched by the ESP32 before accepting commands.
+        self.send_stop_command()
🤖 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 `@robot/beast/ros2_ws/src/ugv_main/ugv_bringup/ugv_bringup/ugv_bringup.py`
around lines 113 - 136, Update the initialization flow in the constructor around
base_controller creation so send_stop_command() is called unconditionally
immediately after opening the controller and before any conditional handling,
ensuring startup always clears a latched motion command regardless of
allow_motion.
robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_logic.py (1)

85-93: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Make charging-signal loss fail closed.

_seen_charging_topic starts false, so the charging lock is not added until SafetyMonitor._on_charging receives a message. A missing, late, or non-republishing /ugv/charging_active publisher therefore leaves allow_motion=true while charging may be active. Add a stale or missing-signal lock, or cover an always-present initial state and heartbeat in tests.

🤖 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 `@robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_logic.py`
around lines 85 - 93, Update SafetyDecision.evaluate so a missing or stale
charging signal fails closed instead of allowing motion: add LOCK_CHARGING when
_seen_charging_topic is false or the signal heartbeat has expired, while
retaining the active-charging lock for valid true signals. Use the existing
charging-state and timeout symbols in SafetyMonitor, and cover initial absence
and signal-loss behavior in tests.
🤖 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 `@robot/beast/ros2_ws/deploy/systemd/beast-ros-base.service`:
- Line 15: Update the systemd unit’s Description field to identify startup as
motion-enabled and interlock-monitored, replacing the outdated “zero-motion
staging” wording; leave the ExecStart command unchanged.
- Line 15: Make the safety-monitor contract explicit in all motion-enabled entry
points: update beast-ros-base.service#15 to pass use_safety_monitor:=true and
interlock_override:=false to ros2 launch, and update the bringup_lidar.launch.py
argument forwarding in nav.launch.py#164-172 and slam_toolbox.launch.py#27-32 to
pass use_safety_monitor: 'true' and interlock_override: 'false'.

In `@robot/beast/ros2_ws/src/ugv_main/ugv_bringup/launch/bringup_lidar.launch.py`:
- Around line 74-87: Update the bringup launch configuration around
allow_motion_arg and use_safety_monitor_arg so motion cannot remain enabled when
use_safety_monitor is false: either reject that argument combination during
launch or derive an effective allow_motion value of false. Preserve
interlock_override as the only explicit maintenance bypass.

In `@robot/beast/ros2_ws/src/ugv_main/ugv_bringup/ugv_bringup/ugv_bringup.py`:
- Line 113: Update the declare_parameter call in the UGV bringup initialization
to pass the boolean default using the supported value=True keyword, and adjust
any source-text assertions that depend on the previous positional spelling.

In `@robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_safety_monitor.py`:
- Around line 146-157: Strengthen the launch-default assertions so both tests
require safety monitoring to be enabled by default. In
robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_safety_monitor.py lines
146-157, add the exact "'use_safety_monitor', default_value='true'" assertion
against text; apply the same assertion to source in
robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_twist_mux_spine.py lines
986-989.

In `@robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_monitor.py`:
- Around line 12-14: Update SafetyMonitor._enforce() so an active interlock
never returns harmlessly when _set_client.service_is_ready() is false; preserve
disarmed/fail-closed behavior until the disarm service becomes available,
including misconfigured service names, or trigger the monitor’s existing
local-stop mechanism and fail-closed state.
- Around line 12-14: Update the safety monitor description to state that it asks
ugv_bringup to disable motion whenever any safety lock is present, including
unknown or unreadable Ethernet carrier state, rather than only when Ethernet or
charging is observed. Keep the existing behavior that the monitor does not
auto-arm after locks clear and ugv_bringup remains the motion authority.

---

Outside diff comments:
In `@robot/beast/ros2_ws/src/ugv_main/ugv_bringup/ugv_bringup/ugv_bringup.py`:
- Around line 113-136: Update the initialization flow in the constructor around
base_controller creation so send_stop_command() is called unconditionally
immediately after opening the controller and before any conditional handling,
ensuring startup always clears a latched motion command regardless of
allow_motion.

In `@robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_logic.py`:
- Around line 85-93: Update SafetyDecision.evaluate so a missing or stale
charging signal fails closed instead of allowing motion: add LOCK_CHARGING when
_seen_charging_topic is false or the signal heartbeat has expired, while
retaining the active-charging lock for valid true signals. Use the existing
charging-state and timeout symbols in SafetyMonitor, and cover initial absence
and signal-loss behavior in tests.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: 4728e077-d167-42c4-a5cb-bf4a772a6444

📥 Commits

Reviewing files that changed from the base of the PR and between 962c8e2 and 179db1b.

📒 Files selected for processing (11)
  • docs/beast-ops.md
  • robot/beast/ros2_ws/deploy/systemd/beast-ros-base.service
  • robot/beast/ros2_ws/deploy/systemd/ugv.env.example
  • robot/beast/ros2_ws/src/ugv_main/ugv_bringup/launch/bringup_lidar.launch.py
  • robot/beast/ros2_ws/src/ugv_main/ugv_bringup/ugv_bringup/ugv_bringup.py
  • robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_safety_monitor.py
  • robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_twist_mux_spine.py
  • robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_logic.py
  • robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_monitor.py
  • robot/beast/ros2_ws/src/ugv_main/ugv_nav/launch/nav.launch.py
  • robot/beast/ros2_ws/src/ugv_main/ugv_slam/launch/slam_toolbox.launch.py

EnvironmentFile=/etc/beast/ugv.env
Environment=PYTHONUNBUFFERED=1
ExecStart=/bin/bash -lc 'source /opt/ros/humble/setup.bash && source /home/beast/beast/RobotOverview/robot/beast/ros2_ws/install/setup.bash && exec ros2 launch ugv_bringup bringup_lidar.launch.py use_lidar:=true use_rviz:=false allow_motion:=false'
ExecStart=/bin/bash -lc 'source /opt/ros/humble/setup.bash && source /home/beast/beast/RobotOverview/robot/beast/ros2_ws/install/setup.bash && exec ros2 launch ugv_bringup bringup_lidar.launch.py use_lidar:=true use_rviz:=false allow_motion:=true'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the unit description for motion-enabled startup.

The Description at Line 2 still says zero-motion staging, but this command starts with allow_motion:=true. systemctl status will display an incorrect safety state. Update the description to state that startup is motion-enabled and interlock-monitored.

🤖 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 `@robot/beast/ros2_ws/deploy/systemd/beast-ros-base.service` at line 15, Update
the systemd unit’s Description field to identify startup as motion-enabled and
interlock-monitored, replacing the outdated “zero-motion staging” wording; leave
the ExecStart command unchanged.

🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Make the safety-monitor contract explicit in every motion-enabled entry point.

All three entry points enable or forward allow_motion without explicitly binding the safety-monitor enable and override values. The current nested defaults are correct, but this safety contract can drift independently.

  • robot/beast/ros2_ws/deploy/systemd/beast-ros-base.service#L15-L15: add use_safety_monitor:=true interlock_override:=false to ExecStart.
  • robot/beast/ros2_ws/src/ugv_main/ugv_nav/launch/nav.launch.py#L164-L172: forward use_safety_monitor: 'true' and interlock_override: 'false' to bringup_lidar.launch.py.
  • robot/beast/ros2_ws/src/ugv_main/ugv_slam/launch/slam_toolbox.launch.py#L27-L32: forward the same explicit safety settings to bringup_lidar.launch.py.
📍 Affects 3 files
  • robot/beast/ros2_ws/deploy/systemd/beast-ros-base.service#L15-L15 (this comment)
  • robot/beast/ros2_ws/src/ugv_main/ugv_nav/launch/nav.launch.py#L164-L172
  • robot/beast/ros2_ws/src/ugv_main/ugv_slam/launch/slam_toolbox.launch.py#L27-L32
🤖 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 `@robot/beast/ros2_ws/deploy/systemd/beast-ros-base.service` at line 15, Make
the safety-monitor contract explicit in all motion-enabled entry points: update
beast-ros-base.service#15 to pass use_safety_monitor:=true and
interlock_override:=false to ros2 launch, and update the bringup_lidar.launch.py
argument forwarding in nav.launch.py#164-172 and slam_toolbox.launch.py#27-32 to
pass use_safety_monitor: 'true' and interlock_override: 'false'.

Comment on lines 74 to +87
allow_motion_arg = DeclareLaunchArgument(
'allow_motion', default_value='false',
'allow_motion', default_value='true',
description=(
'Permit non-zero cmd_vel commands; keep false until physical '
'safety validation passes. Runtime flips go through '
'/ugv/set_allow_motion (ugv_bringup) — never default this true.'
'Permit non-zero cmd_vel commands by default. Active Ethernet or '
'charging interlocks may disable it through /ugv/set_allow_motion.'
)
)

use_safety_monitor_arg = DeclareLaunchArgument(
'use_safety_monitor', default_value='true',
description=(
'Start ugv_safety_monitor (ethernet/charging interlocks as a '
'client of /ugv/set_allow_motion). Does not auto-arm.'
'client of /ugv/set_allow_motion). It disables motion only when '
'an interlock is observed.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift

Reject motion-enabled bringup when the safety monitor is disabled.

When allow_motion is true, use_safety_monitor:=false starts ugv_bringup without a node that observes Ethernet or charging interlocks. Non-zero /cmd_vel commands can then reach the base without interlock enforcement. Reject this combination or force effective allow_motion to false. Keep interlock_override as the only explicit maintenance bypass.

🤖 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 `@robot/beast/ros2_ws/src/ugv_main/ugv_bringup/launch/bringup_lidar.launch.py`
around lines 74 - 87, Update the bringup launch configuration around
allow_motion_arg and use_safety_monitor_arg so motion cannot remain enabled when
use_safety_monitor is false: either reject that argument combination during
launch or derive an effective allow_motion value of false. Preserve
interlock_override as the only explicit maintenance bypass.

self.declare_parameter('wifi_interface', '')
self.declare_parameter('ethernet_interface', '')
self.declare_parameter('allow_motion', False)
self.declare_parameter('allow_motion', True)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a keyword for the boolean default.

Ruff FBT003 flags the positional True at Line 113. Use the keyword form supported by the target ROS 2 Humble rclpy.Node.declare_parameter API, for example value=True, and update source-text assertions that depend on the exact call spelling.

🧰 Tools
🪛 Ruff (0.16.0)

[warning] 113-113: Boolean positional value in function call

(FBT003)

🤖 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 `@robot/beast/ros2_ws/src/ugv_main/ugv_bringup/ugv_bringup/ugv_bringup.py` at
line 113, Update the declare_parameter call in the UGV bringup initialization to
pass the boolean default using the supported value=True keyword, and adjust any
source-text assertions that depend on the previous positional spelling.

Source: Linters/SAST tools

Comment on lines +146 to 157
def test_bringup_launch_defaults_motion_enabled_and_wires_monitor():
launch = (
Path(__file__).resolve().parents[2]
/ 'ugv_bringup'
/ 'launch'
/ 'bringup_lidar.launch.py'
)
text = launch.read_text(encoding='utf-8')
assert "'allow_motion', default_value='false'" in text
assert "'allow_motion', default_value='true'" in text
assert 'ugv_safety_monitor' in text
assert 'use_safety_monitor' in text
assert "'interlock_override', default_value='false'" in text

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

Make the launch tests fail when the safety monitor is disabled by default.

Both tests check only for names or symbols. They do not require use_safety_monitor to default to true, so a motion-enabled launch could lose interlock monitoring while both tests pass.

  • robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_safety_monitor.py#L146-L157: assert "'use_safety_monitor', default_value='true'" in text.
  • robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_twist_mux_spine.py#L986-L989: assert the same exact launch default in source.
📍 Affects 2 files
  • robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_safety_monitor.py#L146-L157 (this comment)
  • robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_twist_mux_spine.py#L986-L989
🤖 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 `@robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_safety_monitor.py`
around lines 146 - 157, Strengthen the launch-default assertions so both tests
require safety monitoring to be enabled by default. In
robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_safety_monitor.py lines
146-157, add the exact "'use_safety_monitor', default_value='true'" assertion
against text; apply the same assertion to source in
robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/test/test_twist_mux_spine.py lines
986-989.

Comment on lines +12 to +14
Normal bringup starts motion-enabled. When Ethernet or charging is observed,
this monitor asks ugv_bringup to disable motion. It does not auto-arm when an
interlock later clears; ugv_bringup remains the sole motion authority.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Make an unavailable disarm service fail closed.

SafetyMonitor._enforce() returns when self._set_client.service_is_ready() is false at Lines 140-141. With allow_motion now true, an active interlock is not enforced during service discovery or when the service name is misconfigured. Keep ugv_bringup disarmed until the service is ready, or make service unavailability trigger a local stop and fail-closed state.

🤖 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 `@robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_monitor.py`
around lines 12 - 14, Update SafetyMonitor._enforce() so an active interlock
never returns harmlessly when _set_client.service_is_ready() is false; preserve
disarmed/fail-closed behavior until the disarm service becomes available,
including misconfigured service names, or trigger the monitor’s existing
local-stop mechanism and fail-closed state.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Describe unknown Ethernet state as a lock.

SafetyState.evaluate() in robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_logic.py treats ethernet_carrier=None as LOCK_ETHERNET; Lines 87-90 also document missing or unreadable carrier state as fail closed. The phrases “when Ethernet is observed” and “disables only active locks” omit this disarm path. State that the monitor disarms when a lock is present, including unknown carrier state.

Also applies to: 106-108

🤖 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 `@robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/safety_monitor.py`
around lines 12 - 14, Update the safety monitor description to state that it
asks ugv_bringup to disable motion whenever any safety lock is present,
including unknown or unreadable Ethernet carrier state, rather than only when
Ethernet or charging is observed. Keep the existing behavior that the monitor
does not auto-arm after locks clear and ugv_bringup remains the motion
authority.

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

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants