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
424 changes: 424 additions & 0 deletions docs/source/device/camera/sensing.rst

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/source/device/cameras/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ camera feeds to clients, see :doc:`/references/camera_streaming`.
:titlesonly:

oak
/device/camera/sensing
4 changes: 4 additions & 0 deletions src/plugins/sensing/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Cached downloads: the jetson_multimedia_api deb, the Jetson_SIPL_API tarball
# and a sparse clone of SENSING's driver repo (.drivers-repo, reached through
# the flat SG8A-AGON-G2Y-A1-JetPack7.2.1 symlink). ~80 MB, refetched when absent.
.cache/
13 changes: 13 additions & 0 deletions src/plugins/sensing/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!--
SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->

# SENSING scripts

Keep launchers that primarily compose Docker commands in Bash.
Keep machine-readable output on stdout and diagnostics on stderr.

Maintain one root README for the plugin overview, source map, and config provenance.
Link to the published GitHub Pages user guide, not its RST source.
Setup procedures and troubleshooting belong in that guide, not in both files.
40 changes: 40 additions & 0 deletions src/plugins/sensing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->

# SENSING GMSL cameras

SENSING connects GMSL cameras to Jetson through the SG8A carrier. This
integration uses NVIDIA SIPL for camera access and provides the tooling to
provision and validate the rig on the host or in a container.

Start with the [SENSING user guide](https://nvidia.github.io/IsaacCapture/main/device/camera/sensing.html)
for supported hardware, installation, container usage, and troubleshooting.
That guide owns the operating instructions; this README maps the source tree.

- [`scripts/`](scripts/): host setup, validation, diagnostics, and the Bash
Docker launcher. Each entry point exposes `--help`.
- [`docker/`](docker/): example image, image-side group configuration, and
container SDK provisioning.
- [`configs/`](configs/): the platform configuration and its provenance.

## Platform configuration provenance

[`configs/shw5g.json`](configs/shw5g.json) is a byte-identical copy supplied
by SENSING for the two-SHW5G rig, from:

```text
SG8A_AGON_G2Y_A1_AGX_ORIN_S56C_SHW5G_SHF3L_SIPL_JP7.2.1_L4TR39.2.1
/query/sg8a_agth_g2a/shw5g.json
```

The public driver package includes only the mixed-camera configurations,
`s56c_shf3l_mixed.json` and `shw5g_shf3l_mixed.json`, not this `SHW5G_2`
configuration. Vendoring it makes validation independent of a downloaded
vendor package.

Keep the file byte-identical to the vendor copy. Compare new vendor drops
before replacing it; do not hand-edit the board wiring. Its CSI ports, I2C
buses, deserializer addresses, GPIOs, and link modes must match the installed
SIPL drivers.
259 changes: 259 additions & 0 deletions src/plugins/sensing/configs/shw5g.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
{
"deserializers": [
{
"name": "MAX96712_Fusa_nv_AB",
"description": "Maxim MAX96712 GMSL2 Deserializer - CSI-AB",
"i2cAddress": "0x29"
},
{
"name": "MAX96712_Fusa_nv_CD",
"description": "Maxim MAX96712 GMSL2 Deserializer - CSI-CD",
"i2cAddress": "0x2d"
}
],
"serializers": [
{
"name": "MAX9295",
"description": "Maxim MAX9295D Serializer",
"i2cAddress": "0x40",
"useCDIv2API": true
},
{
"name": "MAX96717F",
"description": "Maxim MAX96717F Serializer",
"i2cAddress": "0x40",
"useCDIv2API": true
},
{
"name": "MAX96717",
"description": "Maxim MAX96717 Serializer",
"i2cAddress": "0x40",
"useCDIv2API": true
}
],
"imageSensors": [
{
"name": "VB1940",
"description": "SHW5G link2/3 VB1940 physical 0x10",
"i2cAddress": "0x10",
"virtualChannels": [
{
"cfa": "gbrg",
"embeddedTopLines": 1,
"embeddedBottomLines": 0,
"inputFormat": "raw10",
"width": 2560,
"height": 1984,
"fps": 60.0,
"isEmbeddedDataTypeEnabled": true
}
],
"isTriggerModeEnabled": true,
"isTPGEnabled": false,
"useCDIv2API": true
}
],
"platformTransportSettings": [
{
"name": "jetson-thor",
"description": "Thor - Jetson AGX Thor Devkit (p3834)",
"boardIdPrefix": "p3834",
"enableMasks": ["0x0000", "0x1100"],
"transportSettings": [
{
"name": "transportSettings_jetson-thor_AB",
"type": "GMSL",
"description": "GMSL CSI-AB with external MAX96712",
"csiPort": "csi-gh",
"phyMode": "dphy",
"desTxPort": 1,
"deserInfo": {
"name": "Max96712GmslDeserializer",
"i2cAddress": "0x2d"
},
"powerControlInfo": {
"deserializerInfo": {
"name": "TegraDeserPowerDriver",
"gpioPinIndex": 9043968
}
},
"i2cDevice": 10,
"desI2CPort": 0,
"groupInitProg": true
},
{
"name": "transportSettings_jetson-thor_CD",
"type": "GMSL",
"description": "GMSL CSI-CD with external MAX96712",
"csiPort": "csi-cd",
"phyMode": "dphy",
"desTxPort": 1,
"deserInfo": {
"name": "Max96712GmslDeserializer",
"i2cAddress": "0x29"
},
"powerControlInfo": {
"deserializerInfo": {
"name": "TegraDeserPowerDriver",
"gpioPinIndex": 3211264
}
},
"i2cDevice": 9,
"desI2CPort": 0,
"groupInitProg": true
}
]
}
],
"cameraConfigs": [
{
"name": "SHW5G_2",
"type": "GMSL",
"description": "MAX96712 (CSI-CD / CN1): link2/link3 SHW5G mono",
"cameraModules": [
{
"name": "SHW5G_MIX_L2",
"linkIndex": 2,
"transportIndex": 1
},
{
"name": "SHW5G_MIX_L3",
"linkIndex": 3,
"transportIndex": 1
}
],
"transportSettings": [
{
"name": "transportSettings_jetson-thor_AB",
"type": "GMSL",
"csiPort": "csi-gh",
"phyMode": "dphy",
"desTxPort": 1,
"deserInfo": {
"name": "Max96712GmslDeserializer",
"i2cAddress": "0x2d"
},
"powerControlInfo": {
"deserializerInfo": {
"name": "TegraDeserPowerDriver",
"gpioPinIndex": 9043968
}
},
"i2cDevice": 10,
"desI2CPort": 0,
"groupInitProg": false
},
{
"name": "transportSettings_jetson-thor_CD",
"type": "GMSL",
"csiPort": "csi-cd",
"phyMode": "dphy",
"desTxPort": 1,
"deserInfo": {
"name": "Max96712GmslDeserializer",
"i2cAddress": "0x29"
},
"powerControlInfo": {
"deserializerInfo": {
"name": "TegraDeserPowerDriver",
"gpioPinIndex": 3211264
}
},
"i2cDevice": 9,
"desI2CPort": 0,
"groupInitProg": true
}
]
},
{
"name": "SHW5G_MIX_L2",
"type": "GMSL",
"description": "SHW5G mono on physical link2, output VC2",
"moduleDriverName": "SHW5G",
"serInfo": {
"name": "MAX96717",
"i2cAddress": "0x40"
},
"linkMode": "LINK_MODE_GMSL2_6GBPS",
"fsyncMode": "osc_manual",
"mipiSettings": {
"dphyRate": 2500000,
"phyMode": "dphy"
},
"sensorInfo": [
{
"name": "VB1940",
"id": 2,
"description": "SHW5G link2 sensor",
"i2cAddress": "0x10",
"numContext": 1,
"isTriggerModeEnabled": true,
"deviceIndex": 0,
"virtualChannels": [
{
"vcIdSrc": 2,
"vcIdDst": 2,
"cfa": "gbrg",
"embeddedTopLines": 1,
"embeddedBottomLines": 0,
"inputFormat": "raw10",
"width": 2560,
"height": 1984,
"fps": 60.0,
"isEmbeddedDataTypeEnabled": true
}
]
}
],
"eepromInfo": {
"name": "BR24H128",
"i2cAddress": "0x50"
}
},
{
"name": "SHW5G_MIX_L3",
"type": "GMSL",
"description": "SHW5G mono on physical link3, output VC3",
"moduleDriverName": "SHW5G",
"serInfo": {
"name": "MAX96717",
"i2cAddress": "0x40"
},
"linkMode": "LINK_MODE_GMSL2_6GBPS",
"fsyncMode": "osc_manual",
"mipiSettings": {
"dphyRate": 2500000,
"phyMode": "dphy"
},
"sensorInfo": [
{
"name": "VB1940",
"id": 3,
"description": "SHW5G link3 sensor",
"i2cAddress": "0x10",
"numContext": 1,
"isTriggerModeEnabled": true,
"deviceIndex": 0,
"virtualChannels": [
{
"vcIdSrc": 3,
"vcIdDst": 3,
"cfa": "gbrg",
"embeddedTopLines": 1,
"embeddedBottomLines": 0,
"inputFormat": "raw10",
"width": 2560,
"height": 1984,
"fps": 60.0,
"isEmbeddedDataTypeEnabled": true
}
]
}
],
"eepromInfo": {
"name": "BR24H128",
"i2cAddress": "0x50"
}
}
]
}
35 changes: 35 additions & 0 deletions src/plugins/sensing/docker/Dockerfile.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# A container that can reach the SENSING cameras. Built and started by
# run_docker_example.sh; the point is to be read, then borrowed from.
#
# Two things go in the image, and only two:
# - the runtime libraries nvsipl_camera links against but the NVIDIA container
# runtime does not inject (it carries the BSP, not the base OS)
# - the group membership, via image_setup.sh
#
# Everything else -- driver mounts, device access, the NVIDIA capabilities --
# is a container-create option and lives in run_docker_example.sh.
#
# No SIPL drivers are installed here. They are bind-mounted from the host, so
# a vendor update on the host needs no rebuild.

ARG BASE=ubuntu:24.04
FROM ${BASE}

# nvsipl_camera needs EGL: NvBufSurfaceMapEglImage is how a SIPL buffer reaches
# CUDA, so EGL is on the path even with nothing on screen. Absent, it fails at
# load with "libEGL.so.1: cannot open shared object file".
RUN apt-get update && apt-get install -y --no-install-recommends \
libegl1 libgles2 libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*

# Host gids owning /dev/i2c-*, /dev/gpiochip* and /dev/nvmap. Defaults are this
# rig's; run_docker_example.sh passes the real ones, read off the nodes.
# No --group-add is needed at run time: Docker resolves supplementary groups
# from this /etc/group, which covers PID 1 and `docker exec` alike.
ARG SENSING_USER=root
ARG SENSING_GIDS="114:i2c 985:gpio 44:video"
RUN --mount=type=bind,source=image_setup.sh,target=/tmp/image_setup.sh \
/tmp/image_setup.sh "${SENSING_USER}" ${SENSING_GIDS}
38 changes: 38 additions & 0 deletions src/plugins/sensing/docker/image_setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Image-side setup for SIPL capture: put the container user in the groups that
# own the host's camera device nodes. Run as root from a Dockerfile RUN.
#
# This is the whole of it -- no --group-add needed on `docker run`. Docker
# resolves supplementary groups for the container user from the image's own
# /etc/group, so membership set here reaches PID 1 and `docker exec` alike.
# The reverse is not true: --group-add only reaches PID 1, because `docker exec`
# ignores HostConfig.GroupAdd.
#
# Usage:
# image_setup.sh USER GID:NAME [GID:NAME ...]
#
# Get the gids for a specific host with: ./run_docker_example.sh --print-gids

set -euo pipefail

[[ $# -ge 2 ]] || { echo "usage: $0 USER GID:NAME [GID:NAME ...]" >&2; exit 2; }
user="$1"; shift

id "$user" >/dev/null 2>&1 || { echo "$0: no such user: $user" >&2; exit 1; }

for spec in "$@"; do
gid="${spec%%:*}"; name="${spec##*:}"
[[ "$gid" =~ ^[0-9]+$ ]] || { echo "$0: bad spec: $spec" >&2; exit 2; }
# Adopt whatever group already holds the gid rather than assuming the name
# is free -- base images vary, and the kernel checks the number anyway.
if getent group "$gid" >/dev/null; then
name="$(getent group "$gid" | cut -d: -f1)"
else
groupadd --gid "$gid" "$name"
fi
usermod -aG "$name" "$user"
echo " $user -> $name($gid)"
done
Loading
Loading