Skip to content

Add ssh push command for cam_streamer and expose camera outputs#241

Merged
farbod-nv merged 3 commits intomainfrom
fm/cam_push
Mar 11, 2026
Merged

Add ssh push command for cam_streamer and expose camera outputs#241
farbod-nv merged 3 commits intomainfrom
fm/cam_push

Conversation

@farbod-nv
Copy link
Contributor

@farbod-nv farbod-nv commented Mar 10, 2026

Adds push and push-config for rtp camera streaming
Exposes camera output in subgraph for data collection purposes

Summary by CodeRabbit

  • New Features

    • Remote deployment support: deploy to a robot over SSH with new command-line options and sensible defaults.
    • New push and push-config commands to send code or config and restart the remote sender.
    • Default camera mode switched to single-camera.
    • Camera frame outputs are now exposed to parent applications.
  • Documentation

    • Help text and examples updated to show workstation vs robot/local workflows and remote options.

@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bbf9c820-4a13-498d-8fcf-d1260d7dcbb0

📥 Commits

Reviewing files that changed from the base of the PR and between b7ff358 and 1c84dfd.

📒 Files selected for processing (1)
  • examples/camera_streamer/teleop_camera_subgraph.py

📝 Walkthrough

Walkthrough

Added SSH-based remote push and config-push commands to examples/camera_streamer/camera_streamer.sh, changed default config to config/single_camera.yaml, and exposed decoded camera outputs via TeleopCameraSubgraph.camera_output_names backed by _camera_output_names.

Changes

Cohort / File(s) Summary
Remote deployment & CLI
examples/camera_streamer/camera_streamer.sh
Changed DEFAULT_CONFIG to config/single_camera.yaml. Added DEFAULT_ROBOT_IP, DEFAULT_ROBOT_USER, REMOTE_BUILD_DIR. Added parse_remote_opts, cmd_push, and cmd_push_config. Extended command dispatch with push and push-config, updated help/examples; implements rsync/SSH push, optional remote build (--skip-build), and optional deploy suppression (--no-deploy).
Camera outputs accessor
examples/camera_streamer/teleop_camera_subgraph.py
Added _camera_output_names: List[str] and a public camera_output_names property. In compose(), exposed monitored camera outputs as interface ports and populated _camera_output_names.

Sequence Diagram(s)

sequenceDiagram
    participant User as User/Workstation
    participant Script as camera_streamer.sh
    participant Robot as Remote Robot (SSH)
    participant Build as Remote Build
    participant Deploy as Remote Deploy/Container

    User->>Script: run `push --ip <robot_ip> --user <user> [--skip-build] [--no-deploy]`
    Script->>Script: parse_remote_opts (ip,user,config,flags)
    Script->>Robot: create REMOTE_BUILD_DIR & rsync source/config
    Robot-->>Script: ack source/config received

    alt skip-build not set
        Script->>Robot: trigger remote build in REMOTE_BUILD_DIR
        Robot->>Build: build artifacts
        Build-->>Robot: build complete
        Robot-->>Script: build artifacts ready
    end

    alt no-deploy not set
        Script->>Robot: restart/start sender container with config & receiver-host
        Robot->>Deploy: start container
        Deploy-->>Robot: container running
        Robot-->>Script: deploy complete
    end

    Script-->>User: operation finished
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped a script across the wire so fleet,
Pushed configs, built, and nudged a tiny fleet,
Outputs named and ports unfurled with glee,
Streams flow afar from workstation to tree,
A rabbit cheers — deploys done swiftly! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly corresponds to the two main changes: adding SSH push commands (push and push-config) for camera streaming and exposing camera outputs as interface ports.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fm/cam_push

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/camera_streamer/camera_streamer.sh`:
- Around line 20-21: DEFAULT_ROBOT_USER is set to "nvidia" and REMOTE_BUILD_DIR
is "/tmp/isaac-teleop-camera-build", which causes cmd_deploy_sender() to mount
an ephemeral host path; change REMOTE_BUILD_DIR to a persistent directory (e.g.,
under the robot user's home using DEFAULT_ROBOT_USER, such as
/home/${DEFAULT_ROBOT_USER}/isaac-teleop-camera-build or another durable path)
so the container's bind-mount source survives reboots and --restart
unless-stopped can recover the sender; update any usage of REMOTE_BUILD_DIR in
cmd_deploy_sender() and related deploy logic to reference the new persistent
path.
- Around line 231-251: The cmd_push_config flow can leave the container bound to
a different config path; update cmd_push_config to SSH into the remote and
inspect the sender container's mounts (use docker inspect on
SENDER_CONTAINER_NAME) and extract the container-side mounted file path, compare
that mount destination with the requested $CONFIG under $REMOTE_DIR; if they
differ, either refuse the push with an error message explaining the mismatch (do
not scp/restart) or perform a full redeploy of the sender (remove and recreate
the container using the requested mount) — implement this check after
parse_remote_opts and before scp/ssh restart so you either abort or redeploy
based on the mount comparison.
- Around line 105-114: In parse_remote_opts(), each case that dereferences $2
for options --ip, --user, --receiver-host, and --config must first validate that
a value exists and is not another option; follow the same guard used in
cmd_deploy_sender: check [[ $# -lt 2 || "$2" == -* ]] and call log_error with an
appropriate message before shifting and assigning the variable. Update the cases
for _REMOTE_IP, _REMOTE_USER, RECEIVER_HOST, and CONFIG to perform this
validation and only then set the variable and shift 2; leave the boolean flags
(--skip-build, --no-deploy) unchanged.

In `@examples/camera_streamer/teleop_camera_subgraph.py`:
- Around line 304-312: camera_outputs currently returns monitor paths (from
monitored_outputs/VideoStreamMonitorOp.frame_out) which causes downstream
consumers to get substituted placeholder frames; instead expose the real
pre-monitor frame sources via a separate mapping (e.g. _source_outputs) and have
camera_outputs return that. Add and populate _source_outputs in the compose
helpers: in _compose_local_sources set source_outputs[display_key] = (src_op,
src_port) and in _compose_rtp_sources set source_outputs[display_key] =
(decoder, "frame"); keep monitored_outputs as-is for visualization but ensure
camera_outputs (the `@property` camera_outputs) returns self._source_outputs (or
the new mapping) so downstream data-collection gets the decoder/source frames
rather than VideoStreamMonitorOp.frame_out.
- Around line 304-312: The camera_outputs property currently returns the live
backing dict _camera_outputs which allows external mutation; change
camera_outputs to return a shallow copy or an immutable view instead (e.g.,
dict(self._camera_outputs) or types.MappingProxyType(self._camera_outputs)) so
callers cannot modify internal state after compose() has run; update the
property implementation in the camera_outputs getter to return the
copied/readonly mapping while still documenting that the mapping is available
after compose().

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 660a01b8-dee3-432e-9fd9-a8dc867faa4d

📥 Commits

Reviewing files that changed from the base of the PR and between c5c32ed and 94abe6f.

📒 Files selected for processing (2)
  • examples/camera_streamer/camera_streamer.sh
  • examples/camera_streamer/teleop_camera_subgraph.py

@farbod-nv farbod-nv merged commit dbd7cf5 into main Mar 11, 2026
33 checks passed
@farbod-nv farbod-nv deleted the fm/cam_push branch March 11, 2026 00:21
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.

2 participants