refactor(bench): remove the Hawkeye viewer tee

The --viewer path (tee MAVLink frames to UDP and enable the
HIL_STATE_QUATERNION/HIL_ACTUATOR_CONTROLS streams so Hawkeye could
render an SIH flight live) was never validated end to end: Hawkeye
never actually rendered from it. Rather than ship an unproven feature,
drop it.

Removes px4bench.attach_viewer_tee (and its function-local socket use),
the flight_mission --viewer/--viewer-port args, the viewer tee call and
the stream-enable block, and the now-unused --board-dev arg that only
fed those stream commands. The SIH flight logic, firmware gate,
storage/serial tests, and the arming gate are unchanged. README and the
bench testing docs page drop the Hawkeye section and all --viewer
mentions.

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
This commit is contained in:
Ramon Roche
2026-07-07 20:29:01 -07:00
parent bf7dcb7229
commit ca47db5faa
4 changed files with 7 additions and 68 deletions

View File

@@ -38,7 +38,7 @@ Tools/bench_test/
run_bench_suite.py # orchestrator for the non-interactive bench tests
px4bench/ # shared library package
__init__.py # Reporter, connect, MavlinkShell, reboot/replug,
# viewer tee, mavlink-status parsers,
# mavlink-status parsers,
# pymavlink add_message workaround
params.py # param read/set/drain/echo, int32 union encoding
missions.py # mission items, upload/download/compare/clear
@@ -178,8 +178,7 @@ over SERIAL_CONTROL. MAVSDK abstracts exactly those layers away, and adds an
asyncio runtime plus the mavsdk_server gRPC binary as dependencies. The one
plausible candidate was flight orchestration in `sih/flight_mission.py`, but
that test also depends on the nsh shell (arming via `commander`, explicit
`param save`, enabling viewer streams) and on teeing raw frames to a viewer,
neither of which MAVSDK exposes. Verdict: pymavlink everywhere.
`param save`), which MAVSDK does not expose. Verdict: pymavlink everywhere.
## Risk map
@@ -334,9 +333,8 @@ Skips with a warning when the firmware lacks `serial_test`
```
./sih/flight_mission.py CONNECTION [-b BAUD] [--airframe N] [--alt M]
[--viewer] [--viewer-port PORT] [--keep-config]
[--allow-arming] [--expect-hash PREFIX]
[--board-dev DEV] [--report-dir DIR]
[--keep-config] [--allow-arming]
[--expect-hash PREFIX] [--report-dir DIR]
```
Switches the board to a SIH airframe (`SYS_AUTOSTART=1100`, `SYS_HITL=2`,
@@ -344,9 +342,7 @@ physics simulated on the FMU, `pwm_out_sim` in place of real outputs), flies
takeoff, a 3-waypoint square, and RTL as an auto mission with per-phase
timeouts (arming, airborne, waypoint progression, touchdown, auto-disarm),
downloads the flight ULog, and restores the original configuration even on
failure. `--viewer` tees every MAVLink frame to UDP so Hawkeye
(`hawkeye -udp 19410 -mc`) renders the flight live from the serial-connected
board.
failure.
Runs last in the default suite and works standalone. Before doing anything
it probes the live firmware for the SIH module (`simulator_sih status`); if

View File

@@ -2,8 +2,8 @@
Core primitives every test builds on: MAVLink connection setup, PASS/FAIL
reporting, a non-interactive nsh shell over SERIAL_CONTROL (pattern from
Tools/mavlink_shell.py), reboot and USB re-detection helpers, a live viewer
tee, and small parsers for `mavlink status` output.
Tools/mavlink_shell.py), reboot and USB re-detection helpers, and small
parsers for `mavlink status` output.
Protocol-area helpers live in submodules:
px4bench.params parameter read/set/echo with PX4's int32 union encoding
@@ -407,32 +407,6 @@ def arming_gate(allow_arming, action='run the SIH flight test'):
return False
def attach_viewer_tee(conn, host='127.0.0.1', port=19410):
"""Forward every received MAVLink frame to a UDP endpoint, one frame per
datagram (same framing the SITL viewer channel uses), so Hawkeye can
watch a serial-connected board live: hawkeye -udp <port>.
Wraps conn.recv_msg rather than logfile_raw because logfile_raw gets raw
read() chunks, which would split frames across datagrams.
"""
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
addr = (host, port)
orig_recv_msg = conn.recv_msg
def recv_msg_tee():
msg = orig_recv_msg()
if msg is not None:
try:
sock.sendto(msg.get_msgbuf(), addr)
except OSError:
pass
return msg
conn.recv_msg = recv_msg_tee
return conn
def send_reboot(mav):
"""Request an autopilot reboot (MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN, param1=1)."""
mav.mav.command_long_send(

View File

@@ -10,10 +10,6 @@ auto-disarm, all on real NuttX scheduling. The physics is simulated; real
sensor drivers and real outputs are not exercised (pwm_out_sim replaces them,
so nothing on the output rails is ever driven).
With --viewer, every received MAVLink frame is teed to UDP (default 19410)
and the SIH viewer streams are enabled on the board, so a locally running
Hawkeye (`hawkeye -udp 19410 -mc`) renders the flight live.
Requires firmware built with CONFIG_MODULES_SIMULATION_SIMULATOR_SIH=y.
"""
@@ -350,16 +346,9 @@ def main():
add_connection_args(parser)
parser.add_argument('--airframe', type=int, default=SIH_QUAD_AIRFRAME,
help='SIH airframe SYS_AUTOSTART (default: %(default)s)')
parser.add_argument('--board-dev', default='/dev/ttyACM0',
help='mavlink device name ON the board for stream '
'commands (default: %(default)s)')
parser.add_argument('--alt', type=float, default=20.0,
help='takeoff/waypoint altitude AMSL-relative m '
'(default: %(default)s)')
parser.add_argument('--viewer', action='store_true',
help='tee MAVLink to UDP and enable SIH viewer streams '
'(watch with: hawkeye -udp 19410 -mc)')
parser.add_argument('--viewer-port', type=int, default=19410)
parser.add_argument('--keep-config', action='store_true',
help='stay on the SIH airframe when done')
parser.add_argument('--expect-hash', metavar='PREFIX', default=None,
@@ -437,10 +426,6 @@ def main():
if original_autostart is None or report.num_failed > 0:
return report.finish()
if args.viewer:
px4bench.attach_viewer_tee(mav, port=args.viewer_port)
report.info('viewer tee on udp:127.0.0.1:{}'.format(args.viewer_port))
# One shell session for the whole flight, torn down in finally so an
# error path never leaks the firmware nsh task.
shell = MavlinkShell(mav)
@@ -448,15 +433,6 @@ def main():
report.fail('shell', 'could not open nsh shell')
return report.finish()
try:
if args.viewer:
for cmd in ('mavlink stream -d {} -s HIL_STATE_QUATERNION -r 25'
.format(args.board_dev),
'mavlink stream -d {} -s HIL_ACTUATOR_CONTROLS -r 200'
.format(args.board_dev)):
shell_cmd(report, shell, cmd, 'viewer_stream')
report.info('viewer streams on; watch with: hawkeye -udp {} -mc'
.format(args.viewer_port))
ok = fly(report, mav, shell, args.alt, report_dir)
if not ok:
# Best effort: never leave a (simulated) vehicle armed.

View File

@@ -88,13 +88,6 @@ The flight log is downloaded into the report directory automatically for post-fl
Real outputs are replaced by `pwm_out_sim` in this mode, so nothing is driven on the output rails; still, run it only on a bare bench board with nothing connected to the outputs.
The firmware must be built with `CONFIG_MODULES_SIMULATION_SIMULATOR_SIH=y` (boards may provide a bench variant that adds it, such as `px4_fmu-v6xrt_bench`).
To watch the flight live in 3D, install [Hawkeye](https://github.com/PX4/Hawkeye) and run the test with `--viewer`:
```sh
hawkeye -udp 19410 -mc &
./sih/flight_mission.py /dev/ttyACM0 --viewer
```
## Baseline Comparison
`boot_health` can diff two report directories, comparing uORB publication rates, work queues, and topics between runs: