Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/vehicle_teleop/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
logs/
thirdparty/
python/.venv/
.venv/
2 changes: 1 addition & 1 deletion examples/vehicle_teleop/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
cmake_minimum_required(VERSION 3.20)

include(${CMAKE_SOURCE_DIR}/cmake/InstallPythonExample.cmake)
install_python_example(DESTINATION examples/vehicle_teleop/python)
install_python_example(DESTINATION examples/vehicle_teleop)

if(BUILD_TESTING AND BUILD_PYTHON_BINDINGS AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_subdirectory(tests)
Expand Down
39 changes: 31 additions & 8 deletions examples/vehicle_teleop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,24 @@ cmake --build build --parallel 4
cmake --install build
```

Create the example virtual environment from this directory. The scripts use
`.venv/bin/python` directly, so keep the virtual environment at
`examples/vehicle_teleop/.venv`.
Create the example virtual environment in this directory, install the
`isaaccapture` build into it, then install the example:

```bash
cd examples/vehicle_teleop
uv venv --python 3.11 .venv
uv pip install --python .venv/bin/python --find-links ../../build/wheels "isaaccapture[cloudxr]"
# Replace 3.11 with your ISAAC_TELEOP_PYTHON_VERSION and X.Y with the first two numbers of VERSION.
uv venv --python 3.11 --seed .venv
source .venv/bin/activate
cd python
uv sync --active --inexact --no-install-project --no-install-package isaaccapture
cd ..
uv pip install "isaaccapture[cloudxr]==X.Y+local" --find-links=../../install/wheels/ --reinstall-package isaaccapture
uv pip install -e .
```

This is the install from [step 4 of Build from source](https://nvidia.github.io/IsaacCapture/main/development/build_from_source/index.html#install-the-isaaccapture-pip-package),
which [Running an example](../README.md#running-an-example) also uses, except
that the venv lives in this directory because the scripts call
`.venv/bin/python`. Rerun the `isaaccapture` line after every rebuild to replace
the installed wheel.

Clone the vehicle-side dependencies into this example's `thirdparty` directory. These repositories are intentionally not added as git submodules.

```bash
Expand Down Expand Up @@ -119,10 +123,29 @@ If the remote worker was started with `--log-mcap`, replay the recorded commands

The replay command prints the retargeted vehicle command values. It does not write to PandaRunner.

## Running the Modules Directly

The example has no single entry point: each script in `scripts/` runs one module
with `.venv/bin/python -m`. To run a module yourself, from this directory:

```bash
.venv/bin/python -m isaaccapture_examples.vehicle_teleop.isaac_remote_steering_worker
.venv/bin/python -m isaaccapture_examples.vehicle_teleop.isaac_keyboard_control_worker
PYTHONPATH=thirdparty/opendbc:thirdparty/panda .venv/bin/python -m isaaccapture_examples.vehicle_teleop.panda_worker --connect "tcp://<remote-ip>:5555"
.venv/bin/python -m isaaccapture_examples.vehicle_teleop.replay_command_mcap logs/vehicle_control.mcap
```

The Panda worker needs `thirdparty/opendbc` and `thirdparty/panda` on
`PYTHONPATH`; `run_panda_worker.sh` sets that for you.

## Troubleshooting

If the steering worker cannot find the native plugin, pass `--plugin-binary` explicitly. In a source build, the default location is usually `build/src/plugins/steering_wheel/steering_wheel_plugin`. In an install tree, it is usually `plugins/steering_wheel/steering_wheel_plugin`.

The default `--config` and `--plugin-binary` are found relative to this example directory, so they resolve in a source checkout set up as in [Setup](#setup) and in an install tree. If you installed the example as a regular, non-editable package, pass both explicitly, with `--config` pointing at this directory's `config/steering_wheel_config.yaml`.

If the worker fails while creating the OpenXR session, confirm that the CloudXR runtime is running, the CloudXR environment has been sourced in the worker terminal, and the OpenXR client is connected.

If the Panda worker cannot import `opendbc` or `panda`, confirm the two dependency repositories were cloned under `examples/vehicle_teleop/thirdparty/`.

If `python -m` reports `No module named 'isaaccapture_examples'`, the example is not installed in that virtual environment. Rerun `uv pip install -e .` from [Setup](#setup).
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "vehicle-teleop-example"
# The dist name mirrors the import path, so an installed example claims no bare
# top-level name in site-packages.
name = "isaaccapture-examples-vehicle-teleop"
version = "0.0.0"
description = "Isaac Teleop vehicle steering and Panda control example"
requires-python = ">=3.11,<3.14"
Expand All @@ -21,5 +27,11 @@ dependencies = [
"websockets>=17.3",
]

# `only-include` + `sources`, not `packages`, and no __init__.py above
# vehicle_teleop -- see the packaging rules in examples/README.md.
[tool.hatch.build.targets.wheel]
only-include = ["python/isaaccapture_examples/vehicle_teleop"]
sources = ["python"]

[[tool.uv.index]]
url = "https://pypi.nvidia.com"
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from mcap.reader import make_reader
from mcap.writer import CompressionType, Writer

from vehicle_teleop.vehicle_command import VehicleControlCommand
from .vehicle_command import VehicleControlCommand


@dataclass(frozen=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
)
from isaaccapture.schema import SteeringWheelOutput

from vehicle_teleop.vehicle_command import (
from .vehicle_command import (
VehicleControlCommand,
clamp,
isaac_command_to_wire_command,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
)
from isaaccapture.schema import SteeringWheelOutput

from vehicle_teleop.command_log import McapCommandLogger, SteeringWheelSample
from vehicle_teleop.vehicle_command import (
from .command_log import McapCommandLogger, SteeringWheelSample
from .vehicle_command import (
VehicleControlCommand,
isaac_command_to_wire_command,
)
Expand All @@ -46,7 +46,9 @@


def example_root() -> Path:
return Path(__file__).resolve().parents[2]
# Four levels up is the example root, where config/ sits -- in the source
# tree and in the install tree alike.
return Path(__file__).resolve().parents[3]


def default_config_path() -> Path:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import zmq

from vehicle_teleop.vehicle_command import VehicleControlCommand, clamp
from .vehicle_command import VehicleControlCommand, clamp


DEFAULT_CONNECT = "tcp://127.0.0.1:5555"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import argparse
import time

from vehicle_teleop.command_log import McapCommandLogReader
from .command_log import McapCommandLogReader


class CommandMcapReplay:
Expand Down
4 changes: 2 additions & 2 deletions examples/vehicle_teleop/scripts/replay_command_mcap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ PYTHON="${EXAMPLE_ROOT}/.venv/bin/python"

if [[ ! -x "${PYTHON}" ]]; then
echo "Missing example virtual environment: ${EXAMPLE_ROOT}/.venv" >&2
echo "Create it with: uv venv --python 3.11 .venv" >&2
echo "Set it up as in Setup in ${EXAMPLE_ROOT}/README.md" >&2
exit 1
fi

export PYTHONPATH="${EXAMPLE_ROOT}/python${PYTHONPATH:+:${PYTHONPATH}}"

exec "${PYTHON}" -m vehicle_teleop.replay_command_mcap \
exec "${PYTHON}" -m isaaccapture_examples.vehicle_teleop.replay_command_mcap \
"$@"
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ PYTHON="${EXAMPLE_ROOT}/.venv/bin/python"

if [[ ! -x "${PYTHON}" ]]; then
echo "Missing example virtual environment: ${EXAMPLE_ROOT}/.venv" >&2
echo "Create it with: uv venv --python 3.11 .venv" >&2
echo "Set it up as in Setup in ${EXAMPLE_ROOT}/README.md" >&2
exit 1
fi

export PYTHONPATH="${EXAMPLE_ROOT}/python${PYTHONPATH:+:${PYTHONPATH}}"

exec "${PYTHON}" -m vehicle_teleop.isaac_keyboard_control_worker \
exec "${PYTHON}" -m isaaccapture_examples.vehicle_teleop.isaac_keyboard_control_worker \
--rate-hz 50 \
"$@"
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ PYTHON="${EXAMPLE_ROOT}/.venv/bin/python"

if [[ ! -x "${PYTHON}" ]]; then
echo "Missing example virtual environment: ${EXAMPLE_ROOT}/.venv" >&2
echo "Create it with: uv venv --python 3.11 .venv" >&2
echo "Set it up as in Setup in ${EXAMPLE_ROOT}/README.md" >&2
exit 1
fi

export PYTHONPATH="${EXAMPLE_ROOT}/python${PYTHONPATH:+:${PYTHONPATH}}"

exec "${PYTHON}" -m vehicle_teleop.isaac_remote_steering_worker \
exec "${PYTHON}" -m isaaccapture_examples.vehicle_teleop.isaac_remote_steering_worker \
--rate-hz 50 \
"$@"
4 changes: 2 additions & 2 deletions examples/vehicle_teleop/scripts/run_panda_worker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ PYTHON="${EXAMPLE_ROOT}/.venv/bin/python"

if [[ ! -x "${PYTHON}" ]]; then
echo "Missing example virtual environment: ${EXAMPLE_ROOT}/.venv" >&2
echo "Create it with: uv venv --python 3.11 .venv" >&2
echo "Set it up as in Setup in ${EXAMPLE_ROOT}/README.md" >&2
exit 1
fi

export PYTHONPATH="${EXAMPLE_ROOT}/python:${EXAMPLE_ROOT}/thirdparty/opendbc:${EXAMPLE_ROOT}/thirdparty/panda${PYTHONPATH:+:${PYTHONPATH}}"

exec "${PYTHON}" -m vehicle_teleop.panda_worker \
exec "${PYTHON}" -m isaaccapture_examples.vehicle_teleop.panda_worker \
"$@"
4 changes: 4 additions & 0 deletions examples/vehicle_teleop/tests/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ dev = ["pytest", "numpy", "mcap>=1.2.0", "pyyaml", "pyzmq"]

[tool.pytest.ini_options]
pythonpath = ["../python"]

# uv reads settings from the nearest [tool.uv], so this empty table keeps the
# example's pypi.nvidia.com index one directory up out of the test run.
[tool.uv]
6 changes: 3 additions & 3 deletions examples/vehicle_teleop/tests/test_workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
VehicleControlRetargeterConfig,
)

from vehicle_teleop.isaac_keyboard_control_worker import (
from isaaccapture_examples.vehicle_teleop.isaac_keyboard_control_worker import (
IsaacKeyboardControlState,
IsaacKeyboardControlWorker,
TerminalKeyReader,
)
from vehicle_teleop.isaac_remote_steering_worker import (
from isaaccapture_examples.vehicle_teleop.isaac_remote_steering_worker import (
IsaacRemoteSteeringWorker,
build_parser,
)
from vehicle_teleop.vehicle_command import VehicleControlCommand
from isaaccapture_examples.vehicle_teleop.vehicle_command import VehicleControlCommand


@pytest.fixture
Expand Down
Loading