feat: ugv_strike vehicle profile for full-capability UGV testing - #317
Conversation
Adds a committed [vehicle.ugv_strike] profile enabling autonomous evaluation, servo tracking, and continuous strike approach for ground vehicle testing. Shipping it as a vehicle profile rather than config.ini defaults means it survives deploy.sh, which stashes local changes before every pull. Wires the autonomous strike callback per-profile: ugv_strike uses the continuous ApproachMode.STRIKE path, which re-targets a moving vehicle every frame. Other profiles keep the existing one-shot waypoint handler. Fixes a re-entry defect in the continuous path: _handle_approach_strike_command returned False when an approach was already active, and autonomous.evaluate only refreshes its cooldown when strike_cb returns truthy. Once the 30s cooldown expired mid-strike, every subsequent frame logged a spurious AUTONOMOUS STRIKE FAILED. Re-striking the track already under approach is now idempotent; a different track is still refused. Declares reserved_channels explicitly, since vehicle profiles do not inherit and its absence silently skips the servo channel-conflict guard. Drop and RF hunt remain blocked on #147; untouched. Co-authored-by: Claude <noreply@anthropic.com>
_autonomous_strike_handler runs in the detection loop on every frame and read self._vehicle directly. Pre-existing fixtures construct Pipeline by patching __init__ without setting _vehicle, which the codebase already defends against in _refuse_approach_for_fw; the bare access would raise AttributeError inside the loop. Also matches _is_fw_profile's normalization contract so a HYDRA_VEHICLE value of UGV_STRIKE does not silently fall back to the one-shot handler. Co-authored-by: Claude <noreply@anthropic.com>
|
CI FAIL — flake8 + pytest fast suite ( |
|
CI PASS — flake8 + pytest fast suite ( |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9221309a98
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| autonomous.safe_mode = HOLD | ||
| autonomous.default_features = detect,mavlink,tak_output,logging | ||
|
|
||
| [vehicle.ugv_strike] |
There was a problem hiding this comment.
Preserve shared-battery graceful stop for UGV strike
This new UGV profile does not set shared_battery = true. Because vehicle profiles do not inherit and Pipeline defaults _shared_battery to false when the active [vehicle.<name>] section omits the key, shared-pack UGV/truck kits selected with HYDRA_VEHICLE=ugv_strike will not wire the BatteryMonitor LOW-transition callback, so a low propulsion pack only gets the STATUSTEXT path instead of commanding HOLD and safing the servo tracker like the existing [vehicle.ugv] profile. Add shared_battery = true here unless this strike truck has a separate companion battery.
Useful? React with 👍 / 👎.
| autonomous.safe_mode = HOLD | ||
| autonomous.default_features = detect,mavlink,tak_output,logging | ||
|
|
||
| [vehicle.ugv_strike] |
There was a problem hiding this comment.
Add the UGV strike profile to factory config
[vehicle.ugv_strike] is added only to config.ini, but factory reset and fresh factory configs are sourced from config.ini.factory. After a dashboard/API factory reset or on images created from the factory file, setting HYDRA_VEHICLE=ugv_strike will hit the unknown-profile path and run the base config with autonomy disabled and servo tracking off instead of this strike profile. Mirror this section into config.ini.factory and include that file in the regression coverage.
Useful? React with 👍 / 👎.
Enables the full detection-to-strike chain on the SORCC UGV kits for the Week 5 AI block, shipped as a committed vehicle profile.
Why a vehicle profile, not config.ini defaults
scripts/deploy.shrunsgit stashbefore every pull andconfig.iniis tracked, so on-box config edits are silently stashed on update. A[vehicle.*]section ships in the repo and survives every pull. Each kit selects it with one line in/etc/hydra/vehicle.env.What it turns on
Autonomous evaluation, servo tracking, truck/car target classes, GUIDED, operator-locked targeting, and a 25 km geofence centred on the operating area so the fence is satisfied without constraining the test.
Geofence cannot be disabled:
_has_valid_geofence()requires a polygon or nonzero lat/lon, and both_eval_autonomy_liveand_eval_autonomy_dryrunreject every detection without one. A non-binding fence is the supported way to get out of its way.Strike path selection
_handle_strike_commandsends one GUIDED waypoint at an estimated target GPS and misses a moving target._handle_approach_strike_commandrunsApproachMode.STRIKE, re-targeting continuously.ugv_strikeis wired to the continuous path; every other profile keeps the existing one-shot behavior.Defects found and fixed during review
autonomous.evaluateonly refreshes its cooldown whenstrike_cbreturns truthy, and the approach handler returned False whenever an approach was already active. Once the 30 s cooldown expired mid-strike, every subsequent frame logged a spuriousAUTONOMOUS STRIKE FAILEDand recorded a reject decision. Re-striking the track already under approach is now idempotent; a different track is still refused.reserved_channelsdropped. Vehicle profiles do not inherit —bootstrap.pyreads only the named section.reserved_channelsis a vehicle-local key read withfallback="", so omitting it skips the servo and light-bar channel-conflict guard rather than failing loudly. On the truck, 1 and 3 are steering and throttle. Now declared explicitly, with a test pinning it to[vehicle.ugv]._autonomous_strike_handlerruns every frame and readself._vehicledirectly; fixtures that patch__init__never set it, which_refuse_approach_for_fwalready defends against. Now uses the samegetattridiom and matches_is_fw_profile's case normalization.Out of scope
_eval_dropand_eval_rf_huntremain unconditionally BLOCKED on #147; untouched.Verification
2654 passed, flake8 clean. The 19 failures / 10 errors in
test_ota_verify_pull.pyandtest_tak_pytak_emitter.pyare pre-existing on the dev box (missingpytak) and reproduce identically on a clean tree. Every new test was confirmed red before its fix and green after.Follow-up, not fixed here
autonomous.notify_strike_complete()(autonomous.py:565) clears_strike_in_progress, but it has no callers anywhere and the flag is never read as a gate. Write-only dead state; the cooldown is the only real re-entry control.