Skip to content

feat(falcon): v0.3.0 — rate PID + closed-loop pure-Rust SITL#14

Merged
avrabe merged 1 commit into
mainfrom
falcon/v0.3
May 19, 2026
Merged

feat(falcon): v0.3.0 — rate PID + closed-loop pure-Rust SITL#14
avrabe merged 1 commit into
mainfrom
falcon/v0.3

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented May 19, 2026

Summary

The inner control loop closes. v0.3 adds a body-rate PID stabilizer and a pure-Rust closed-loop SITL bench that drives the v0.2 EKF + v0.3 PID against a rigid-body plant and verifies convergence on three scenarios — all deterministic, all in CI.

What's in

  • crates/relay-rate — 3-axis body-rate PID with clamp-and-hold anti-windup. no_std + no_alloc. 13 unit + proptest cases.
  • examples/falcon-sitl-hover — pure-Rust closed-loop SITL bench. Plant + EKF + rate PID closed-loop; 3 scenarios (step / disturbance / hover); 5 integration tests.
  • FV-FALCON-RATE-001 — v0.3 verification artifact, 5 extractable steps.
  • FEAT-FALCON-v0.3 bumped pendingapproved with achieved metrics inline.

Achieved on this branch

scenario convergence overshoot RMS-steady
step [0.5, -0.3, 0.4] rad/s 0.139 s 1.2 % 0.0012 rad/s
disturbance (1 rad/s impulse) 0.141 s recovery
hover from [0.7, -0.5, 0.3] 0.175 s
check result
cargo test --workspace 55 suites green (was 52 in v0.2)
cargo test -p relay-rate 13/13 PASS (13 unit + 2 proptest at 256 / 4096 fuzz)
cargo test -p falcon-sitl-hover 5/5 PASS
cargo run -p falcon-sitl-hover --release PASS on all 3 scenarios
Verification gate ✅ 5/5 artifacts, 18/18 steps
rivet validate 0 broken cross-references

Test plan

  • CI green on this PR (all 7 checks)
  • Verification gate posts ✅ 5/5 sticky comment
  • cargo run -p falcon-sitl-hover --release locally prints PASS for all 3 scenarios

After merge

TAG=falcon-v0.3.0 bash scripts/tag-and-release.sh

Scope note — Gazebo slipped to v0.4

Gazebo Harmonic SITL was originally scoped for v0.3, but pure-Rust SITL ships now because it:

  • runs in CI without a 1 GB Gazebo install
  • produces byte-identical results given a seed
  • isolates the controller test from sim-framework noise

Real Gazebo lockstep arrives with v0.4 where the full attitude cascade (relay-att) makes a real hover meaningful. The pure-Rust SITL stays in tree as the fast-iteration test rig.

Other v0.3 items pushed to v0.4: Lean Lyapunov proof of rate loop (needs rules_lean wiring), Kani bounded-overflow check, tokio-rs/loom on host bridge (no bridge yet), rerun.io evidence (lands with Gazebo).

🤖 Generated with Claude Code

The inner control loop closes. v0.2's EKF estimates attitude, v0.3's
new rate PID drives commanded body rates, a pure-Rust rigid-body
plant integrates dynamics — full closed loop converges in-process,
deterministic given a seed, runs in CI without a Gazebo install.

What lands:

Crates
- relay-rate — body-rate PID stabilizer. 3-axis, no_std + no_alloc.
  Clamp-and-hold anti-windup (RATE-P01). NaN-safe input handling
  (RATE-P02). Step-response convergence on a pure-integrator plant
  within 2 s with <0.01 rad/s steady-state error (RATE-P03 surrogate).
  Defaults tuned for a 500 g, 10-inch quad at 1 kHz. 13 unit +
  proptest cases.

Example
- examples/falcon-sitl-hover — pure-Rust closed-loop SITL bench.
  Rigid-body plant (rotational dynamics + quaternion integration)
  + v0.2 EKF + v0.3 rate PID, three scenarios:
    step:        setpoint [0.5,-0.3,0.4] rad/s → converges in 0.139 s
                 with 1.2 % overshoot, 0.0012 rad/s RMS-steady
    disturbance: 1 rad/s impulse recovered in 0.141 s
    hover:       initial rates [0.7,-0.5,0.3] → settled in 0.175 s
  CLI: --scenario, --noise σ, --quiet. 5 integration tests.

Rivet
- FV-FALCON-RATE-001 — v0.3 verification artifact with 5 extractable
  fields.steps. Brings the falcon gate from 4 → 5 artifacts (13 → 18
  steps).
- FEAT-FALCON-v0.3 bumped pending → approved, achieved metrics inline.

Verification posture
- cargo test --workspace: 55 test suites green (was 52 in v0.2)
- python3 scripts/run-falcon-verification.py: ✅ 5/5, 18/18 steps green
- cargo run -p falcon-sitl-hover --release: PASS on all 3 scenarios
- rivet validate: 0 broken cross-references

Scope notes — what slipped to v0.4
- Gazebo Harmonic SITL: pure-Rust SITL ships now because it runs in CI
  without Gazebo install + produces byte-identical results given a seed.
  Gazebo lockstep proper makes more sense once relay-att joins (v0.4)
  for a full hover.
- Lean Lyapunov formal proof on the rate loop — v0.4 with rules_lean.
- Kani bounded-overflow on PID arithmetic — v0.4.
- tokio-rs/loom on host bridge — v0.5 once the bridge exists.
- rerun.io .rrd evidence — v0.4 with the SITL hookup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

running 16 tests
test tests::cross_of_parallel_is_zero ... ok
test tests::ekf_p01_tick_preserves_unit_quaternion ... ok
test tests::ekf_p02_extreme_accel_does_not_produce_nan ... ok
test tests::ekf_p02_zero_accel_does_not_produce_nan ... ok
test tests::ekf_p03_innovation_monotone_with_tilt_disagreement ... ok
test tests::ekf_p04_static_rest_converges_to_gravity_aligned ... ok
test tests::ekf_p05_pure_yaw_gyro_does_not_destabilise_attitude ... ok
test tests::fresh_estimator_is_at_identity ... ok
test tests::normalise_nan_returns_none ... ok
test tests::normalise_zero_returns_none ... ok
test tests::quat_mul_identity_left ... ok
test tests::quat_mul_identity_right ... ok
test tests::rotate_inverse_identity_passes_through ... ok
test tests::ekf_p01_property ... ok
test tests::bias_estimate_bounded ... ok
test tests::ekf_p02_property_sequence ... ok

test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 16 tests
test tests::cross_of_parallel_is_zero ... ok
test tests::ekf_p01_tick_preserves_unit_quaternion ... ok
test tests::ekf_p02_extreme_accel_does_not_produce_nan ... ok
test tests::ekf_p02_zero_accel_does_not_produce_nan ... ok
test tests::ekf_p03_innovation_monotone_with_tilt_disagreement ... ok
test tests::ekf_p04_static_rest_converges_to_gravity_aligned ... ok
test tests::ekf_p05_pure_yaw_gyro_does_not_destabilise_attitude ... ok
test tests::fresh_estimator_is_at_identity ... ok
test tests::normalise_nan_returns_none ... ok
test tests::normalise_zero_returns_none ... ok
test tests::quat_mul_identity_left ... ok
test tests::ekf_p01_property ... ok
test tests::quat_mul_identity_right ... ok
test tests::rotate_inverse_identity_passes_through ... ok
test tests::ekf_p02_property_sequence ... ok
test tests::bias_estimate_bounded ... ok

test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 16 tests
test tests::cross_of_parallel_is_zero ... ok
test tests::ekf_p01_tick_preserves_unit_quaternion ... ok
test tests::ekf_p02_extreme_accel_does_not_produce_nan ... ok
test tests::ekf_p02_zero_accel_does_not_produce_nan ... ok
test tests::ekf_p03_innovation_monotone_with_tilt_disagreement ... ok
test tests::ekf_p04_static_rest_converges_to_gravity_aligned ... ok
test tests::ekf_p05_pure_yaw_gyro_does_not_destabilise_attitude ... ok
test tests::fresh_estimator_is_at_identity ... ok
test tests::normalise_nan_returns_none ... ok
test tests::normalise_zero_returns_none ... ok
test tests::quat_mul_identity_left ... ok
test tests::quat_mul_identity_right ... ok
test tests::rotate_inverse_identity_passes_through ... ok
test tests::bias_estimate_bounded ... ok
test tests::ekf_p01_property ... ok
test tests::ekf_p02_property_sequence ... ok

test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.66s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 5 tests
test tests::phases_are_consistent_with_trajectory_duration ... ok
test tests::quat_error_is_zero_for_identical_quaternions ... ok
test tests::rotate_ned_to_body_identity_passes_through ... ok
test tests::deterministic_bench_passes ... ok
test tests::noisy_bench_passes_loose ... ok

test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

--- noise=0 (deterministic) ---
samples 5000
RMS error (full) 3.306°
RMS error (steady) 3.312° (last 2.5 s)
peak error 19.804°
final error 3.023°
convergence time 0.68s (first sustained <5°)
estimator wall time 480 µs
NaN/∞ seen false
falcon-ekf-bench: PASS

running 13 tests
test tests::at_zero_error_output_is_zero ... ok
test tests::fresh_pid_has_zero_state ... ok
test tests::negative_error_drives_negative_torque ... ok
test tests::out_of_range_dt_clamped_safely ... ok
test tests::positive_error_drives_positive_torque ... ok
test tests::rate_p02_infinite_setpoint_does_not_propagate ... ok
test tests::rate_p02_nan_input_does_not_propagate ... ok
test tests::output_clamped_to_torque_max ... ok
test tests::rate_p03_step_response_drives_error_to_zero ... ok
test tests::reset_clears_state ... ok
test tests::rate_p02_property ... ok
test tests::rate_p01_anti_windup_holds_integral_at_bound ... ok
test tests::rate_p01_property ... ok

test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 13 tests
test tests::at_zero_error_output_is_zero ... ok
test tests::fresh_pid_has_zero_state ... ok
test tests::negative_error_drives_negative_torque ... ok
test tests::out_of_range_dt_clamped_safely ... ok
test tests::positive_error_drives_positive_torque ... ok
test tests::rate_p02_infinite_setpoint_does_not_propagate ... ok
test tests::rate_p02_nan_input_does_not_propagate ... ok
test tests::output_clamped_to_torque_max ... ok
test tests::rate_p03_step_response_drives_error_to_zero ... ok
test tests::reset_clears_state ... ok
test tests::rate_p02_property ... ok
test tests::rate_p01_property ... ok
test tests::rate_p01_anti_windup_holds_integral_at_bound ... ok

test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 13 tests
test tests::at_zero_error_output_is_zero ... ok
test tests::fresh_pid_has_zero_state ... ok
test tests::out_of_range_dt_clamped_safely ... ok
test tests::negative_error_drives_negative_torque ... ok
test tests::positive_error_drives_positive_torque ... ok
test tests::rate_p02_infinite_setpoint_does_not_propagate ... ok
test tests::rate_p02_nan_input_does_not_propagate ... ok
test tests::output_clamped_to_torque_max ... ok
test tests::rate_p03_step_response_drives_error_to_zero ... ok
test tests::reset_clears_state ... ok
test tests::rate_p01_anti_windup_holds_integral_at_bound ... ok
test tests::rate_p02_property ... ok
test tests::rate_p01_property ... ok

test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.50s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 5 tests
test tests::deterministic_disturbance_recovers ... ok
test tests::deterministic_hover_settles ... ok
test tests::plant_step_preserves_unit_quaternion ... ok
test tests::deterministic_step_response_passes ... ok
test tests::noisy_step_response_still_passes ... ok

test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

--- scenario: step ---
samples 5000
final ω (rad/s) [+0.5007, -0.3003, +0.4006]
peak ω above sp 0.0061 rad/s
overshoot 1.2 %
RMS error (steady) 0.0012 rad/s
convergence time 0.139s
loop wall time 529 µs
NaN/∞ seen false
outcome PASS
--- scenario: disturbance ---
samples 5000
final ω (rad/s) [+0.0000, -0.0042, +0.0000]
peak ω above sp 0.8958 rad/s
recovery time 0.141s after impulse
loop wall time 595 µs
NaN/∞ seen false
outcome PASS
--- scenario: hover ---
samples 5000
final ω (rad/s) [-0.0020, +0.0013, -0.0007]
peak ω above sp 0.7683 rad/s
convergence time 0.175s
loop wall time 553 µs
NaN/∞ seen false
outcome PASS
falcon-sitl-hover: PASS

running 9 tests
test tests::args_default_ports_for_vehicle_mode ... ok
test tests::args_default_ports_for_gcs_mode ... ok
test tests::args_rejects_missing_mode ... ok
test tests::args_rejects_unknown_mode ... ok
test tests::handle_inbound_propagates_bad_crc ... ok
test tests::handle_inbound_rejects_unsupported_message ... ok
test tests::handle_inbound_truncated ... ok
test tests::current_timestamp_is_monotone_within_a_run ... ok
test tests::vehicle_and_gcs_exchange_heartbeats_over_udp ... ok

test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s

[falcon-hello-demo] building release binary...
[falcon-hello-demo] launching gcs on 127.0.0.1:14700
[falcon-hello-demo] launching vehicle (4 Hz × 4s)
[falcon-hello-demo] vehicle sent 13 heartbeat(s)
[falcon-hello-demo] gcs received 13 heartbeat(s)
[falcon-hello-demo] PASS

running 9 tests
test tests::fresh_stub_has_zero_time ... ok
test tests::deterministic_across_ticks_with_same_time ... ok
test tests::innovation_is_quiet_in_stub ... ok
test tests::tick_passes_time_through ... ok
test tests::tick_returns_identity_quaternion ... ok
test tests::tick_returns_zero_position_and_velocity ... ok
test tests::unit_quaternion_check_rejects_clearly_non_unit ... ok
test tests::tick_innovation_within_healthy_range ... ok
test tests::tick_always_emits_unit_quaternion ... ok

test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 9 tests
test tests::deterministic_across_ticks_with_same_time ... ok
test tests::fresh_stub_has_zero_time ... ok
test tests::innovation_is_quiet_in_stub ... ok
test tests::tick_passes_time_through ... ok
test tests::tick_returns_identity_quaternion ... ok
test tests::tick_returns_zero_position_and_velocity ... ok
test tests::unit_quaternion_check_rejects_clearly_non_unit ... ok
test tests::tick_always_emits_unit_quaternion ... ok
test tests::tick_innovation_within_healthy_range ... ok

test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 9 tests
test tests::deterministic_across_ticks_with_same_time ... ok
test tests::innovation_is_quiet_in_stub ... ok
test tests::fresh_stub_has_zero_time ... ok
test tests::tick_passes_time_through ... ok
test tests::tick_returns_identity_quaternion ... ok
test tests::tick_returns_zero_position_and_velocity ... ok
test tests::unit_quaternion_check_rejects_clearly_non_unit ... ok
test tests::tick_innovation_within_healthy_range ... ok
test tests::tick_always_emits_unit_quaternion ... ok

test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 33 tests
test crc::tests::accumulate_slice_equals_individual ... ok
test crc::tests::empty_input_keeps_seed ... ok
test crc::tests::mavlink_reference_vector_123456789 ... ok
test crc::tests::order_matters ... ok
test crc::tests::single_byte_zero ... ok
test frame::tests::encode_rejects_payload_length_mismatch ... ok
test frame::tests::encode_rejects_too_small_output ... ok
test frame::tests::frame_msg_id_three_bytes_little_endian ... ok
test frame::tests::frame_payload_length_byte_matches ... ok
test frame::tests::frame_starts_with_magic_v2 ... ok
test frame::tests::peek_message_id_finds_heartbeat ... ok
test frame::tests::peek_rejects_v1_magic ... ok
test frame::tests::rejects_bad_crc ... ok
test frame::tests::rejects_truncated_header ... ok
test frame::tests::rejects_truncated_payload ... ok
test frame::tests::rejects_v1_magic ... ok
test frame::tests::rejects_wrong_crc_extra ... ok
test frame::tests::round_trip_heartbeat_through_frame ... ok
test heartbeat::tests::crc_extra_is_fifty ... ok
test heartbeat::tests::custom_mode_little_endian ... ok
test heartbeat::tests::decode_empty_payload ... ok
test heartbeat::tests::decode_rejects_long_payload ... ok
test heartbeat::tests::decode_rejects_short_payload ... ok
test heartbeat::tests::field_offsets_match_spec ... ok
test heartbeat::tests::mav_mode_flag_or_and_contains ... ok
test heartbeat::tests::payload_length_constant ... ok
test heartbeat::tests::round_trip_falcon_default ... ok
test heartbeat::tests::round_trip_gcs_default ... ok
test heartbeat::tests::round_trip_max_values ... ok
test heartbeat::tests::round_trip_zero ... ok
test heartbeat::tests::round_trip_arbitrary ... ok
test frame::tests::encode_parse_round_trip_arbitrary_seq ... ok
test frame::tests::parser_never_panics ... ok

test result: ok. 33 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 33 tests
test crc::tests::accumulate_slice_equals_individual ... ok
test crc::tests::mavlink_reference_vector_123456789 ... ok
test crc::tests::order_matters ... ok
test crc::tests::empty_input_keeps_seed ... ok
test crc::tests::single_byte_zero ... ok
test frame::tests::encode_rejects_payload_length_mismatch ... ok
test frame::tests::encode_rejects_too_small_output ... ok
test frame::tests::frame_msg_id_three_bytes_little_endian ... ok
test frame::tests::frame_payload_length_byte_matches ... ok
test frame::tests::frame_starts_with_magic_v2 ... ok
test frame::tests::peek_message_id_finds_heartbeat ... ok
test frame::tests::peek_rejects_v1_magic ... ok
test frame::tests::rejects_bad_crc ... ok
test frame::tests::encode_parse_round_trip_arbitrary_seq ... ok
test frame::tests::rejects_truncated_header ... ok
test frame::tests::rejects_truncated_payload ... ok
test frame::tests::rejects_v1_magic ... ok
test frame::tests::rejects_wrong_crc_extra ... ok
test frame::tests::round_trip_heartbeat_through_frame ... ok
test heartbeat::tests::crc_extra_is_fifty ... ok
test heartbeat::tests::custom_mode_little_endian ... ok
test heartbeat::tests::decode_empty_payload ... ok
test heartbeat::tests::decode_rejects_long_payload ... ok
test heartbeat::tests::decode_rejects_short_payload ... ok
test heartbeat::tests::field_offsets_match_spec ... ok
test heartbeat::tests::payload_length_constant ... ok
test heartbeat::tests::mav_mode_flag_or_and_contains ... ok
test heartbeat::tests::round_trip_falcon_default ... ok
test heartbeat::tests::round_trip_gcs_default ... ok
test heartbeat::tests::round_trip_max_values ... ok
test heartbeat::tests::round_trip_zero ... ok
test heartbeat::tests::round_trip_arbitrary ... ok
test frame::tests::parser_never_panics ... ok

test result: ok. 33 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

running 33 tests
test crc::tests::accumulate_slice_equals_individual ... ok
test crc::tests::empty_input_keeps_seed ... ok
test crc::tests::order_matters ... ok
test crc::tests::mavlink_reference_vector_123456789 ... ok
test crc::tests::single_byte_zero ... ok
test frame::tests::encode_rejects_payload_length_mismatch ... ok
test frame::tests::encode_rejects_too_small_output ... ok
test frame::tests::frame_msg_id_three_bytes_little_endian ... ok
test frame::tests::frame_payload_length_byte_matches ... ok
test frame::tests::frame_starts_with_magic_v2 ... ok
test frame::tests::peek_message_id_finds_heartbeat ... ok
test frame::tests::peek_rejects_v1_magic ... ok
test frame::tests::rejects_bad_crc ... ok
test frame::tests::rejects_truncated_header ... ok
test frame::tests::rejects_truncated_payload ... ok
test frame::tests::rejects_v1_magic ... ok
test frame::tests::rejects_wrong_crc_extra ... ok
test frame::tests::round_trip_heartbeat_through_frame ... ok
test heartbeat::tests::crc_extra_is_fifty ... ok
test heartbeat::tests::custom_mode_little_endian ... ok
test heartbeat::tests::decode_empty_payload ... ok
test heartbeat::tests::decode_rejects_long_payload ... ok
test heartbeat::tests::decode_rejects_short_payload ... ok
test heartbeat::tests::field_offsets_match_spec ... ok
test heartbeat::tests::mav_mode_flag_or_and_contains ... ok
test heartbeat::tests::payload_length_constant ... ok
test heartbeat::tests::round_trip_falcon_default ... ok
test heartbeat::tests::round_trip_gcs_default ... ok
test heartbeat::tests::round_trip_max_values ... ok
test heartbeat::tests::round_trip_zero ... ok
test heartbeat::tests::round_trip_arbitrary ... ok
test frame::tests::encode_parse_round_trip_arbitrary_seq ... ok
test frame::tests::parser_never_panics ... ok

test result: ok. 33 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.33s

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

falcon verification gate (filter: (has-tag "falcon"))

5 artifact(s) matched: FV-FALCON-EKF-001, FV-FALCON-RATE-001, FV-FALCON-WORLD-001, FV-FALCON-EKF-STUB-001, FV-FALCON-MAVLINK-001

[ PASS] ( 6.77s) FV-FALCON-EKF-001: cargo test -p relay-ekf
[ PASS] ( 8.96s) FV-FALCON-EKF-001: cargo test -p relay-ekf --release
[ PASS] ( 0.72s) FV-FALCON-EKF-001: PROPTEST_CASES=4096 cargo test -p relay-ekf
[ PASS] ( 0.14s) FV-FALCON-EKF-001: cargo test -p falcon-ekf-bench
[ PASS] ( 0.16s) FV-FALCON-EKF-001: cargo run -q -p falcon-ekf-bench --release
[ PASS] ( 0.37s) FV-FALCON-RATE-001: cargo test -p relay-rate
[ PASS] ( 0.67s) FV-FALCON-RATE-001: cargo test -p relay-rate --release
[ PASS] ( 0.55s) FV-FALCON-RATE-001: PROPTEST_CASES=4096 cargo test -p relay-rate
[ PASS] ( 0.16s) FV-FALCON-RATE-001: cargo test -p falcon-sitl-hover
[ PASS] ( 0.20s) FV-FALCON-RATE-001: cargo run -q -p falcon-sitl-hover --release
[ PASS] ( 0.32s) FV-FALCON-WORLD-001: cargo test -p falcon-hello
[ PASS] ( 4.69s) FV-FALCON-WORLD-001: scripts/falcon-hello-demo.sh
[ PASS] ( 0.31s) FV-FALCON-EKF-STUB-001: cargo test -p relay-ekf-stub
[ PASS] ( 0.60s) FV-FALCON-EKF-STUB-001: cargo test -p relay-ekf-stub --release
[ PASS] ( 0.14s) FV-FALCON-EKF-STUB-001: PROPTEST_CASES=4096 cargo test -p relay-ekf-stub
[ PASS] ( 0.39s) FV-FALCON-MAVLINK-001: cargo test -p relay-mavlink
[ PASS] ( 0.87s) FV-FALCON-MAVLINK-001: cargo test -p relay-mavlink --release
[ PASS] ( 0.39s) FV-FALCON-MAVLINK-001: PROPTEST_CASES=4096 cargo test -p relay-mavlink

✅ Rivet verification gate — falcon

5/5 passed

count
Passed 5
Failed 0
Skipped (no steps) 0

Source of truth: artifacts/verification/FV-FALCON-*.yaml.

@avrabe avrabe merged commit 0ea6145 into main May 19, 2026
7 checks passed
@avrabe avrabe deleted the falcon/v0.3 branch May 19, 2026 16:29
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