From e3f6d5e75ce40994cec7880de69572ab69e86c6a Mon Sep 17 00:00:00 2001 From: Ivan Yang Date: Sat, 24 Oct 2026 15:22:38 -0700 Subject: [PATCH 1/2] feat(cts): conformance test suite and docs for full-body device integrations Add the full-body suite under src/python/isaaccapture/cts/full_body (capture, checker, oracle) on top of the shared core. A take is one recording of a ten-step script the performer paces; the checker reads its core.FullBodyPoseRecord channel with only mcap and flatbuffers and returns pass, fail, retake or insufficient_data. cts/common gains the shared checks and vector helpers only this suite uses. The Device Conformance section gains the Full-Body Suite page, and the overview, setup and submission pages, the docs media tools, the root README and add_device.rst cover both suites. As in the hand suite, an undecodable payload makes the checker exit 4, and the viewer's rate filter uses math.isnan. Signed-off-by: Ivan Yang --- README.md | 2 +- docs/AGENTS.md | 5 +- .../_static/cts/full-body-checker-panel.png | 3 + docs/source/_static/cts/full-body-pacing.svg | 3 + .../_static/cts/full_body/01-a_pose_still.gif | 3 + .../cts/full_body/02-t_pose_hold_open.gif | 3 + .../cts/full_body/03-neutral_stance.gif | 3 + .../cts/full_body/04-left_arm_raise.gif | 3 + .../cts/full_body/05-right_arm_raise.gif | 3 + .../cts/full_body/06-left_leg_raise.gif | 3 + .../cts/full_body/07-right_leg_raise.gif | 3 + .../_static/cts/full_body/08-squat_x2.gif | 3 + .../cts/full_body/09-march_in_place.gif | 3 + .../cts/full_body/10-t_pose_hold_close.gif | 3 + docs/source/conformance/full_body.rst | 352 ++++++++ docs/source/conformance/overview.rst | 53 +- docs/source/conformance/setup.rst | 26 +- docs/source/conformance/submit.rst | 27 +- docs/source/device/add_device.rst | 2 +- docs/tools/cts_media/README.md | 37 +- docs/tools/cts_media/build_pages.py | 134 ++- docs/tools/cts_media/full_body.html | 118 +++ .../common/src/cts_common/checks/coverage.py | 56 ++ .../src/cts_common/checks/timestamps.py | 42 + .../cts/common/src/cts_common/vectors.py | 13 + .../cts/common/tests/test_boundaries.py | 2 +- .../isaaccapture/cts/full_body/README.md | 283 ++++++ .../cts/full_body/capture/README.md | 13 + .../cts/full_body/capture/capture_panel.py | 414 +++++++++ .../cts/full_body/capture/cues.py | 77 ++ .../full_body/capture/cues/a_pose_still.wav | 3 + .../cts/full_body/capture/cues/beep.wav | 3 + .../cts/full_body/capture/cues/closing.wav | 3 + .../cts/full_body/capture/cues/index.json | 17 + .../full_body/capture/cues/index.json.license | 2 + .../full_body/capture/cues/left_arm_raise.wav | 3 + .../full_body/capture/cues/left_leg_raise.wav | 3 + .../full_body/capture/cues/march_in_place.wav | 3 + .../full_body/capture/cues/neutral_stance.wav | 3 + .../capture/cues/right_arm_raise.wav | 3 + .../capture/cues/right_leg_raise.wav | 3 + .../cts/full_body/capture/cues/squat_x2.wav | 3 + .../capture/cues/t_pose_hold_close.wav | 3 + .../capture/cues/t_pose_hold_open.wav | 3 + .../cts/full_body/capture/cues/tick.wav | 3 + .../cts/full_body/capture/live.py | 118 +++ .../cts/full_body/capture/make_labels.py | 265 ++++++ .../cts/full_body/capture/pytest.ini | 15 + .../cts/full_body/capture/record.sh | 63 ++ .../cts/full_body/capture/render.py | 280 ++++++ .../cts/full_body/capture/requirements.txt | 13 + .../cts/full_body/capture/session.py | 25 + .../cts/full_body/capture/setup_env.sh | 44 + .../cts/full_body/capture/steps.py | 206 +++++ .../cts/full_body/capture/tests/test_cues.py | 89 ++ .../full_body/capture/tests/test_record.py | 51 ++ .../cts/full_body/capture/tests/test_steps.py | 156 ++++ .../cts/full_body/checker/.gitignore | 11 + .../cts/full_body/checker/AGENTS.md | 173 ++++ .../cts/full_body/checker/README.md | 208 +++++ .../cts/full_body/checker/pytest.ini | 7 + .../full_body/checker/requirements-dev.txt | 1 + .../full_body/checker/requirements-panel.txt | 7 + .../cts/full_body/checker/requirements.txt | 5 + .../cts/full_body/checker/setup_env.sh | 62 ++ .../checker/src/full_body_cts/__init__.py | 23 + .../checker/src/full_body_cts/_schema.py | 29 + .../src/full_body_cts/checks/__init__.py | 135 +++ .../src/full_body_cts/checks/consistency.py | 58 ++ .../src/full_body_cts/checks/envelope.py | 64 ++ .../src/full_body_cts/checks/geometry.py | 666 ++++++++++++++ .../src/full_body_cts/checks/orientation.py | 195 ++++ .../src/full_body_cts/checks/posture.py | 694 +++++++++++++++ .../src/full_body_cts/checks/segmentation.py | 281 ++++++ .../checker/src/full_body_cts/cli.py | 102 +++ .../checker/src/full_body_cts/frames.py | 56 ++ .../checker/src/full_body_cts/labels.py | 19 + .../checker/src/full_body_cts/mcap_source.py | 97 ++ .../src/full_body_cts/panel/__init__.py | 7 + .../src/full_body_cts/panel/__main__.py | 70 ++ .../checker/src/full_body_cts/panel/app.py | 276 ++++++ .../checker/src/full_body_cts/panel/bundle.py | 41 + .../checker/src/full_body_cts/panel/render.py | 68 ++ .../checker/src/full_body_cts/panel/status.py | 47 + .../checker/src/full_body_cts/panel/track.py | 54 ++ .../checker/src/full_body_cts/profile.py | 177 ++++ .../checker/src/full_body_cts/report.py | 65 ++ .../cts/full_body/checker/tests/conftest.py | 34 + .../checker/tests/known_deviations.py | 83 ++ .../cts/full_body/checker/tests/synth.py | 362 ++++++++ .../checker/tests/test_boundaries.py | 73 ++ .../full_body/checker/tests/test_checks.py | 772 ++++++++++++++++ .../cts/full_body/checker/tests/test_cli.py | 177 ++++ .../full_body/checker/tests/test_oracle.py | 114 +++ .../full_body/checker/tests/test_panel_app.py | 134 +++ .../checker/tests/test_panel_boundary.py | 47 + .../checker/tests/test_panel_bundle.py | 228 +++++ .../checker/tests/test_panel_status.py | 130 +++ .../checker/tests/test_panel_track.py | 158 ++++ .../checker/tests/test_pico_shapes.py | 84 ++ .../checker/tests/test_posture_measurement.py | 371 ++++++++ .../cts/full_body/oracle/.gitignore | 8 + .../cts/full_body/oracle/AGENTS.md | 57 ++ .../cts/full_body/oracle/README.md | 155 ++++ .../cts/full_body/oracle/fixtures_index.json | 831 ++++++++++++++++++ .../cts/full_body/oracle/generate.sh | 28 + .../cts/full_body/oracle/generate_fixtures.py | 693 +++++++++++++++ .../cts/full_body/oracle/mcap_io.py | 88 ++ .../cts/full_body/oracle/posture_fixtures.py | 387 ++++++++ .../cts/full_body/oracle/posture_script.py | 423 +++++++++ .../cts/full_body/oracle/posture_verify.py | 452 ++++++++++ .../cts/full_body/oracle/skeleton.py | 377 ++++++++ .../cts/full_body/oracle/toolchain.py | 24 + .../cts/full_body/oracle/verify_fixtures.py | 635 +++++++++++++ 114 files changed, 13620 insertions(+), 78 deletions(-) create mode 100644 docs/source/_static/cts/full-body-checker-panel.png create mode 100644 docs/source/_static/cts/full-body-pacing.svg create mode 100644 docs/source/_static/cts/full_body/01-a_pose_still.gif create mode 100644 docs/source/_static/cts/full_body/02-t_pose_hold_open.gif create mode 100644 docs/source/_static/cts/full_body/03-neutral_stance.gif create mode 100644 docs/source/_static/cts/full_body/04-left_arm_raise.gif create mode 100644 docs/source/_static/cts/full_body/05-right_arm_raise.gif create mode 100644 docs/source/_static/cts/full_body/06-left_leg_raise.gif create mode 100644 docs/source/_static/cts/full_body/07-right_leg_raise.gif create mode 100644 docs/source/_static/cts/full_body/08-squat_x2.gif create mode 100644 docs/source/_static/cts/full_body/09-march_in_place.gif create mode 100644 docs/source/_static/cts/full_body/10-t_pose_hold_close.gif create mode 100644 docs/source/conformance/full_body.rst create mode 100644 docs/tools/cts_media/full_body.html create mode 100644 src/python/isaaccapture/cts/full_body/README.md create mode 100644 src/python/isaaccapture/cts/full_body/capture/README.md create mode 100644 src/python/isaaccapture/cts/full_body/capture/capture_panel.py create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues.py create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/a_pose_still.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/beep.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/closing.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/index.json create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/index.json.license create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/left_arm_raise.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/left_leg_raise.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/march_in_place.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/neutral_stance.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/right_arm_raise.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/right_leg_raise.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/squat_x2.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/t_pose_hold_close.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/t_pose_hold_open.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/cues/tick.wav create mode 100644 src/python/isaaccapture/cts/full_body/capture/live.py create mode 100644 src/python/isaaccapture/cts/full_body/capture/make_labels.py create mode 100644 src/python/isaaccapture/cts/full_body/capture/pytest.ini create mode 100755 src/python/isaaccapture/cts/full_body/capture/record.sh create mode 100644 src/python/isaaccapture/cts/full_body/capture/render.py create mode 100644 src/python/isaaccapture/cts/full_body/capture/requirements.txt create mode 100644 src/python/isaaccapture/cts/full_body/capture/session.py create mode 100755 src/python/isaaccapture/cts/full_body/capture/setup_env.sh create mode 100644 src/python/isaaccapture/cts/full_body/capture/steps.py create mode 100644 src/python/isaaccapture/cts/full_body/capture/tests/test_cues.py create mode 100644 src/python/isaaccapture/cts/full_body/capture/tests/test_record.py create mode 100644 src/python/isaaccapture/cts/full_body/capture/tests/test_steps.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/.gitignore create mode 100644 src/python/isaaccapture/cts/full_body/checker/AGENTS.md create mode 100644 src/python/isaaccapture/cts/full_body/checker/README.md create mode 100644 src/python/isaaccapture/cts/full_body/checker/pytest.ini create mode 100644 src/python/isaaccapture/cts/full_body/checker/requirements-dev.txt create mode 100644 src/python/isaaccapture/cts/full_body/checker/requirements-panel.txt create mode 100644 src/python/isaaccapture/cts/full_body/checker/requirements.txt create mode 100755 src/python/isaaccapture/cts/full_body/checker/setup_env.sh create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/__init__.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/_schema.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/checks/__init__.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/checks/consistency.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/checks/envelope.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/checks/geometry.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/checks/orientation.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/checks/posture.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/checks/segmentation.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/cli.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/frames.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/labels.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/mcap_source.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/panel/__init__.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/panel/__main__.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/panel/app.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/panel/bundle.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/panel/render.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/panel/status.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/panel/track.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/profile.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/src/full_body_cts/report.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/conftest.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/known_deviations.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/synth.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/test_boundaries.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/test_checks.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/test_cli.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/test_oracle.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/test_panel_app.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/test_panel_boundary.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/test_panel_bundle.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/test_panel_status.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/test_panel_track.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/test_pico_shapes.py create mode 100644 src/python/isaaccapture/cts/full_body/checker/tests/test_posture_measurement.py create mode 100644 src/python/isaaccapture/cts/full_body/oracle/.gitignore create mode 100644 src/python/isaaccapture/cts/full_body/oracle/AGENTS.md create mode 100644 src/python/isaaccapture/cts/full_body/oracle/README.md create mode 100644 src/python/isaaccapture/cts/full_body/oracle/fixtures_index.json create mode 100755 src/python/isaaccapture/cts/full_body/oracle/generate.sh create mode 100644 src/python/isaaccapture/cts/full_body/oracle/generate_fixtures.py create mode 100644 src/python/isaaccapture/cts/full_body/oracle/mcap_io.py create mode 100644 src/python/isaaccapture/cts/full_body/oracle/posture_fixtures.py create mode 100644 src/python/isaaccapture/cts/full_body/oracle/posture_script.py create mode 100644 src/python/isaaccapture/cts/full_body/oracle/posture_verify.py create mode 100644 src/python/isaaccapture/cts/full_body/oracle/skeleton.py create mode 100644 src/python/isaaccapture/cts/full_body/oracle/toolchain.py create mode 100644 src/python/isaaccapture/cts/full_body/oracle/verify_fixtures.py diff --git a/README.md b/README.md index f91473f1e8..8fdc0d6c7e 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Our [documentation page](https://nvidia.github.io/IsaacCapture) provides everyth ### Check a Device Integration -The CTS records one scripted take from a hand-tracking device and checks it against the data a retargeter needs; start with the [hand guide](src/python/isaaccapture/cts/hand/README.md). +The CTS records one scripted take from a hand-tracking or full-body device and checks it against the data a retargeter needs; start with the [hand](src/python/isaaccapture/cts/hand/README.md) or [full-body](src/python/isaaccapture/cts/full_body/README.md) guide. ### Install & Run Isaac Lab diff --git a/docs/AGENTS.md b/docs/AGENTS.md index fcec8663ad..8ee1d9e93e 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -109,8 +109,9 @@ and `logo_dark`. `source/conformance/` and its media are vendor-neutral: no glove, suit or tracker company or product appears in prose, cards, commands, take names or plugin names, because a named -example reads as an endorsement. Use a fictional device (Glove X with `glove_x_plugin`) and -say it is a placeholder. Headsets (PICO, Quest) are the exception: every take runs on one. +example reads as an endorsement. Use a fictional device (Glove X with `glove_x_plugin`, +Suit X with `body.suit-x`) and say it is a placeholder. Headsets (PICO, Quest) are the +exception: every take runs on one. ## Removing cache overrides diff --git a/docs/source/_static/cts/full-body-checker-panel.png b/docs/source/_static/cts/full-body-checker-panel.png new file mode 100644 index 0000000000..6889600d53 --- /dev/null +++ b/docs/source/_static/cts/full-body-checker-panel.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab2662e91c43953441ec1ac2503ba49636081342e57fd785c1eed9f643d7e7bf +size 217862 diff --git a/docs/source/_static/cts/full-body-pacing.svg b/docs/source/_static/cts/full-body-pacing.svg new file mode 100644 index 0000000000..0810c22436 --- /dev/null +++ b/docs/source/_static/cts/full-body-pacing.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09672abb426832f6577811b163dbd6454508295437849b3a6eeae19e807f8d7d +size 10292 diff --git a/docs/source/_static/cts/full_body/01-a_pose_still.gif b/docs/source/_static/cts/full_body/01-a_pose_still.gif new file mode 100644 index 0000000000..6525814bfb --- /dev/null +++ b/docs/source/_static/cts/full_body/01-a_pose_still.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e39cdded5d29a13568ea66f5d3d1e677a669d0a2e867deca655936f65104caed +size 136461 diff --git a/docs/source/_static/cts/full_body/02-t_pose_hold_open.gif b/docs/source/_static/cts/full_body/02-t_pose_hold_open.gif new file mode 100644 index 0000000000..9701e4a439 --- /dev/null +++ b/docs/source/_static/cts/full_body/02-t_pose_hold_open.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:21aa4b6afeec07ba8b4d48cf4d5632f4759c4905955faa3c746685fe8d0ff536 +size 136037 diff --git a/docs/source/_static/cts/full_body/03-neutral_stance.gif b/docs/source/_static/cts/full_body/03-neutral_stance.gif new file mode 100644 index 0000000000..cd362545ca --- /dev/null +++ b/docs/source/_static/cts/full_body/03-neutral_stance.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da241c1d0710328e6e599a65efd6ddff5d76f1b1090e9b7a580b4b9655004a49 +size 122321 diff --git a/docs/source/_static/cts/full_body/04-left_arm_raise.gif b/docs/source/_static/cts/full_body/04-left_arm_raise.gif new file mode 100644 index 0000000000..b1bd61ec0a --- /dev/null +++ b/docs/source/_static/cts/full_body/04-left_arm_raise.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:06554a922204a0a5bdf6fd32bf2863f1e6fc75455b5d5704ab759dc268b01fb9 +size 169180 diff --git a/docs/source/_static/cts/full_body/05-right_arm_raise.gif b/docs/source/_static/cts/full_body/05-right_arm_raise.gif new file mode 100644 index 0000000000..caf49540fc --- /dev/null +++ b/docs/source/_static/cts/full_body/05-right_arm_raise.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:38818f068779e30427922b9ffbb9d454f183b7fa50da210ce2324884bcc44e50 +size 174498 diff --git a/docs/source/_static/cts/full_body/06-left_leg_raise.gif b/docs/source/_static/cts/full_body/06-left_leg_raise.gif new file mode 100644 index 0000000000..d97cf5dc42 --- /dev/null +++ b/docs/source/_static/cts/full_body/06-left_leg_raise.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f5f4f2e60749d7501b405ad292b3fe39e0b98bc4e5c2da807abd7a59ae47141d +size 211280 diff --git a/docs/source/_static/cts/full_body/07-right_leg_raise.gif b/docs/source/_static/cts/full_body/07-right_leg_raise.gif new file mode 100644 index 0000000000..4c0493f7fe --- /dev/null +++ b/docs/source/_static/cts/full_body/07-right_leg_raise.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fdc856823a78ef570944887231bf9f673cda3e744659895272b9040956572f50 +size 205586 diff --git a/docs/source/_static/cts/full_body/08-squat_x2.gif b/docs/source/_static/cts/full_body/08-squat_x2.gif new file mode 100644 index 0000000000..b49fae1065 --- /dev/null +++ b/docs/source/_static/cts/full_body/08-squat_x2.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa6d7fb6b4429823e2c55092ef2122134992a07cf0a126b20e87268610eee87c +size 800322 diff --git a/docs/source/_static/cts/full_body/09-march_in_place.gif b/docs/source/_static/cts/full_body/09-march_in_place.gif new file mode 100644 index 0000000000..26bf639be3 --- /dev/null +++ b/docs/source/_static/cts/full_body/09-march_in_place.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2fd2dcba71bb1403855d1dfa0f688c44c540e004bb2f37f4606a241acdccca30 +size 293609 diff --git a/docs/source/_static/cts/full_body/10-t_pose_hold_close.gif b/docs/source/_static/cts/full_body/10-t_pose_hold_close.gif new file mode 100644 index 0000000000..26ab31555e --- /dev/null +++ b/docs/source/_static/cts/full_body/10-t_pose_hold_close.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c942c42a3ddbc419220f4de095d36f8fbba8368b85f0051e3b622a345a740314 +size 136102 diff --git a/docs/source/conformance/full_body.rst b/docs/source/conformance/full_body.rst new file mode 100644 index 0000000000..aafc569353 --- /dev/null +++ b/docs/source/conformance/full_body.rst @@ -0,0 +1,352 @@ +.. SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +.. SPDX-License-Identifier: Apache-2.0 + +.. _cts-full-body: + +Full-Body Suite +=============== + +The full-body suite records one take of ten standing poses and motions, then checks the +``core.FullBodyPoseRecord`` stream in it: the 24-joint skeleton of the OpenXR +``XR_BD_body_tracking`` extension, pelvis to hands, in the joint order listed in +:doc:`/device/body_tracking/index`. + +- **PICO body tracking** is the default source (``body.pico-xr``). Set up, calibrate and + activate the headset and Motion Trackers as described in :doc:`/device/body_tracking/index`. +- **Your own suit or mocap system** records through a vendor backend and its plugin + (:ref:`vendor-selection`). The backend must publish those 24 indices right-handed, +Y up, in metres, with the subject facing + −Z (:code-file:`oracle/README.md `). + A CloudXR headset must stay connected for the OpenXR session, but it needs no body tracking. + +.. list-table:: At a glance + :widths: 25 75 + + * - Steps + - 10, standing: four held poses and six motions + * - Time + - About 1.5 minutes, plus the time you take to get into each pose + +.. _cts-full-body-pacing: + +How each step runs +------------------ + +.. figure:: /_static/cts/full-body-pacing.svg + :alt: The ten timed steps in a row, and step 2 zoomed in: spoken cue, get into the pose with no time limit, press, beep, hold for the countdown, tick. + :width: 100% + +- **Audio is optional.** The capture panel shows each cue as text. To hear the cues, connect + speakers to the workstation; they do not play in the headset. +- Once the capture panel reads *ready when you are*, press the controller trigger, or space in + the capture panel's browser tab (not the terminal). +- A press at any other moment is ignored on purpose: no reaction, nothing queued. +- A press during the cue cuts the cue short. Press again when you are ready. +- Held poses (steps 1–3, 10): get into the pose, then press. Motions (4–9): press, then move. +- Held-pose measurements use the last 60% of the window, so settle early. + +.. _cts-full-body-steps: + +The ten steps +------------- + +In each motion step, the step's main joint must swing at least 15° +(``segmentation.labelled_step_actually_performed``). Checks marked *measured* only report a +number; they do not decide the verdict. + +.. grid:: 1 2 2 2 + :gutter: 3 + + .. grid-item-card:: 1 · A-pose, still + :img-top: /_static/cts/full_body/01-a_pose_still.gif + :img-alt: A figure standing still with straight arms angled down and out, in an A shape. + + :bdg-secondary:`hold 5 s` *"Arms down. Stand still."* + + Feet hip-width apart, arms straight and angled down away from your sides, eyes ahead. Stay + still until the tick. + + +++ + Not judged on its own; the signal and geometry checks cover the whole take, this window + included. + + .. grid-item-card:: 2 · T-pose + :img-top: /_static/cts/full_body/02-t_pose_hold_open.gif + :img-alt: A figure holding both arms straight out to the sides. + + :bdg-secondary:`hold 6 s` *"T pose. Hold."* + + Both arms straight out to the sides, level with the floor, palms down. Hold still. + + +++ + Measured: how far the arms sit below horizontal and how the two arms differ + (``posture.tpose_arm_droop``, ``posture.tpose_left_right_asymmetry``). + + .. grid-item-card:: 3 · Neutral stance + :img-top: /_static/cts/full_body/03-neutral_stance.gif + :img-alt: A figure standing relaxed with arms down. + + :bdg-secondary:`hold 7 s` *"Arms down. Relax."* + + Lower your arms from the T-pose and stand relaxed and still. + + +++ + Measured: the resting hip angles that the knee raises are compared with + (``posture.contralateral_crosstalk_single_leg_raise``). + + .. grid-item-card:: 4 · Left arm up + :img-top: /_static/cts/full_body/04-left_arm_raise.gif + :img-alt: A figure raising its left arm sideways to overhead and lowering it. + + :bdg-secondary:`move 5 s` *"Left arm up, overhead."* + + After the press, raise your straight left arm sideways to overhead and lower it. Stay upright. + + +++ + Checked: hand at least 60° above the shoulder (``posture.arm_raise_range_of_motion``), + torso lean 6° or less (``performance.arm_raise_torso_stability``), and no other arm or leg + swings 10° more (``segmentation.step_order_matches_labels``). + + .. grid-item-card:: 5 · Right arm up + :img-top: /_static/cts/full_body/05-right_arm_raise.gif + :img-alt: A figure raising its right arm sideways to overhead and lowering it. + + :bdg-secondary:`move 5 s` *"Right arm up, overhead."* + + After the press, raise your straight right arm sideways to overhead and lower it. Stay upright. + + +++ + Checked: hand at least 60° above the shoulder (``posture.arm_raise_range_of_motion``), + torso lean 6° or less (``performance.arm_raise_torso_stability``), and no other arm or leg + swings 10° more (``segmentation.step_order_matches_labels``). + + .. grid-item-card:: 6 · Left knee up + :img-top: /_static/cts/full_body/06-left_leg_raise.gif + :img-alt: A figure lifting its left knee to about hip height and putting it down. + + :bdg-secondary:`move 5 s` *"Left knee up."* + + After the press, lift your left knee to about hip height and lower it. Right foot stays put. + + +++ + Checked: the left hip swings at least 15° and no other arm or leg swings 10° more + (``segmentation.labelled_step_actually_performed``, ``segmentation.step_order_matches_labels``). + Measured: how much the still hip moves (``posture.contralateral_crosstalk_single_leg_raise``). + + .. grid-item-card:: 7 · Right knee up + :img-top: /_static/cts/full_body/07-right_leg_raise.gif + :img-alt: A figure lifting its right knee to about hip height and putting it down. + + :bdg-secondary:`move 5 s` *"Right knee up."* + + After the press, lift your right knee to about hip height and lower it. Left foot stays put. + + +++ + Checked: the right hip swings at least 15° and no other arm or leg swings 10° more + (``segmentation.labelled_step_actually_performed``, ``segmentation.step_order_matches_labels``). + Measured: how much the still hip moves (``posture.contralateral_crosstalk_single_leg_raise``). + + .. grid-item-card:: 8 · Squat twice + :img-top: /_static/cts/full_body/08-squat_x2.gif + :img-alt: A figure squatting slowly and standing up, twice. + + :bdg-secondary:`move 10 s` *"Squat twice, slowly."* + + After the press, squat slowly and stand fully up, twice, same depth, weight on both legs. + + +++ + Checked: hip flexion reaches at least 20° (``performance.squat_depth_sufficient``), the + two reps agree within 20% (``posture.squat_rep_repeatability``), and the knees agree + within 10° at the bottom (``posture.squat_knee_symmetry``). + + .. grid-item-card:: 9 · March in place + :img-top: /_static/cts/full_body/09-march_in_place.gif + :img-alt: A figure marching on the spot, lifting its knees in turn. + + :bdg-secondary:`move 6 s` *"March in place."* + + After the press, lift your knees in turn at a steady pace, without walking forward. + + +++ + Checked: the legs alternate (``posture.march_ankle_antiphase``), and the left knee lifts + at least three times with intervals varying 25% or less + (``performance.march_cadence_steady``). + + .. grid-item-card:: 10 · T-pose again + :img-top: /_static/cts/full_body/10-t_pose_hold_close.gif + :img-alt: A figure holding both arms straight out to the sides again. + + :bdg-secondary:`hold 6 s` *"T pose again. Hold."* + + Same as step 2: arms straight out, level with the floor, palms down. + + +++ + Measured: how far the same pose has drifted since step 2 + (``posture.cumulative_drift_between_tpose_windows``). + +.. _cts-full-body-rehearse: + +Rehearse +-------- + +- **Work in pairs.** One person performs; the other stands at the screen and presses space. + A suit without controllers in hand always needs the space bar. +- **Walk through the cards once** before recording. The figures face you, so their left arm + is on your right. +- **Clear the space** to raise both arms overhead, squat and march without hitting anything. +- **Practice takes cost nothing.** Every take gets its own directory; nothing is overwritten. + +.. _cts-full-body-record: + +Record +------ + +Set up the tools and connect the headset first (:doc:`setup`). Then, from the repository root: + +.. code-block:: bash + + src/python/isaaccapture/cts/full_body/capture/record.sh pico4u + +The first argument names the device and the take. Open the capture panel at the address the run +prints: http://localhost:8081 unless that port was taken, or the ``[capture] headset:`` address +in the headset's browser. Press **Start recording** when the performer is standing ready. The +script begins at the first frame with a valid joint. After 10 s without one, a red box lists what +to check; the take keeps running. + +To record your own device, name the plugin, the vendor backend and its collection. The device +name must come first; ``record.sh`` rejects a leading option with its usage line. ``suitx``, +``suit_x_plugin``, ``body.suit-x`` and ``suit_x`` are placeholders for a fictional Suit X; +replace each with your own: + +.. code-block:: bash + + src/python/isaaccapture/cts/full_body/capture/record.sh suitx \ + --plugin suit_x_plugin \ + --vendor body.suit-x \ + --vendor-param collection_id=suit_x + +- ``--plugin NAME`` is the ``name:`` in the plugin's ``plugin.yaml``, found under + ``install/plugins/`` once installed (``cmake --install build``). ``record.sh`` launches it + with that file's ``args:`` when you press **Start recording**, so do not start it yourself; + do start your suit's own streaming software first. +- ``--vendor`` is the id your backend registers. ``collection_id`` must match the + ``--collection-id=`` in the plugin's ``args:``; omit it if both use the backend's default. A + mismatch records an empty take that looks like a device that never connected. + +After step 10, *"Done. You can stop now."* plays and the capture panel shows a label report: +the first rows check the file; the step rows re-derive seven of the steps from the pelvis, +ankles and hands (A-pose, neutral stance and march have none). One ``BAD`` step row means that +step was mistimed or performed wrongly: record again. Most rows ``BAD`` with numbers like +``pelvis drops 0 cm`` means the joint stream is frozen: look at the device or plugin. A suit +that cannot track the hands flags ``LEFT_HAND`` and ``RIGHT_HAND`` invalid and gets one *all steps BAD* row, fewer than 24 valid joints and an ``n/a`` +arm-raise reach check instead: expected, not a fault. Press Ctrl+C when done. The take is in its +own directory: + +.. code-block:: text + + ~/isaaccapture-cts/pico4u_2026-03-04_101530/ + ├── pico4u_2026-03-04_101530-body.mcap the recording + ├── pico4u_2026-03-04_101530-body.labels.json the step windows + ├── pico4u_2026-03-04_101530-body.json device name, time, repo commit + └── pico4u_2026-03-04_101530-body.log the recorder's output + +Keep the four files together and never rename them: the labels cannot be regenerated. + +.. _cts-full-body-check: + +Check +----- + +Point the checker at the ``.mcap`` inside its take directory, so it finds the labels file +beside it (to check on another machine, copy the whole directory): + +.. code-block:: bash + + src/python/isaaccapture/cts/full_body/checker/.venv/bin/python -m full_body_cts.cli \ + ~/isaaccapture-cts//-body.mcap + +The command prints the verdict and one +line per check, and exits 0 ``pass``, 1 ``fail``, 2 ``retake`` or 3 ``insufficient_data``, or +4 when the check could not run; :ref:`cts-overview-verdicts` says what each means. Add ``--json`` for the machine-readable +report, or run ``--list-checks`` alone to see all 38 checks. The output for a synthetic +reference take, shortened: + +.. code-block:: text + :class: code-100col + + source full_body/oracle/fixtures/posture/posture_golden_full_script.mcap + frames 2050 + topic full_body/full_body schema core.FullBodyPoseRecord + verdict PASS + + [pass] schema.required_field_present.joints joints present on every pose + … + [pass] posture.arm_raise_range_of_motion both hands reach 89 deg above the shoulder + [pass] posture.march_ankle_antiphase the legs alternate (hip correlation -0.68) + [pass] posture.squat_knee_symmetry knees differ by 0.0 deg at depth + [pass] posture.squat_rep_repeatability the two reps agree to 0% of hip flexion + [pass] performance.squat_depth_sufficient the squat reaches 55 deg of hip flexion + [pass] performance.march_cadence_steady cadence holds at 0.90 Hz, step intervals varying 1% + [pass] performance.arm_raise_torso_stability the torso stays within 0.0 deg of upright + +.. _cts-full-body-view: + +View +---- + +The viewer needs the checker environment built with +``full_body/checker/setup_env.sh --panel`` (:doc:`setup`). + +.. code-block:: bash + + src/python/isaaccapture/cts/full_body/checker/.venv/bin/python -m full_body_cts.panel \ + ~/isaaccapture-cts//-body.mcap + +It prints the same report, then serves port 8080, or the next free port; open the address it +prints. ``--host 0.0.0.0`` opens it to other machines. The viewer replays the +skeleton (a joint that lost tracking turns red where it was last seen), plots frame rate and +valid joints over the take, and lists every check by group, with nine key signal and geometry +checks in a *Decides the take* folder on top. Its +**package for submission** button builds the archive you send: see :doc:`submit`. + +.. figure:: /_static/cts/full-body-checker-panel.png + :alt: The full-body viewer: a skeleton in a T-pose on a floor grid, and a sidebar with a + green PASS banner, playback controls, the package for submission button and the checks. + :width: 100% + + The viewer on a synthetic reference take, during the T-pose. + +Troubleshooting +--------------- + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - What you see + - What to do + * - **Start recording** hangs after ``waiting for a system...`` in the terminal + - No headset is connected to CloudXR; connect it (:doc:`setup`) and the take + goes on. Ctrl+C does not work here; close the terminal to get out. + * - *no joint has been valid yet*, then the red *No body data after 10 s* box + - PICO: check body tracking, the trackers and their calibration + (:doc:`/device/body_tracking/index`). Own device: check the plugin is running and + ``collection_id`` matches. + * - A press does nothing + - It came outside *ready when you are*, or the key went to another window. Click the + capture panel page, then press space. + * - The capture panel says **Spoken cues are off** + - ``aplay`` is missing. Install ``alsa-utils`` and restart the panel to hear the cues, or + record with the on-screen cues only. + * - An error naming a Git LFS pointer + - Run ``git lfs pull`` (:doc:`setup`), then record again. + * - *the session did not open: …*, on the capture panel + - Nothing was recorded. *Required plugin … was not discovered*: ``--plugin`` must match the + ``plugin.yaml`` ``name:`` of an installed plugin. *no live vendor* or *does not support + parameter*: the backend is not in the installed wheel, or the ``--vendor-param`` key is + wrong; rebuild and re-run ``capture/setup_env.sh``. Then run ``record.sh`` again. + * - Verdict ``pass``, posture checks ``n/a``, and the note *no motion-step labels beside the + recording* + - The checker found no labels. Run it on the recording in its take directory. + +More in :code-file:`full_body/README.md ` and +:code-file:`full_body/checker/README.md `. diff --git a/docs/source/conformance/overview.rst b/docs/source/conformance/overview.rst index f58f9650fe..159dad25e3 100644 --- a/docs/source/conformance/overview.rst +++ b/docs/source/conformance/overview.rst @@ -6,11 +6,11 @@ Device Conformance Testing ========================== -You have integrated a device that publishes hand poses into Isaac Capture. The Conformance Test -Suite (CTS) produces the evidence that the integration works: you record one scripted take, a -checker reads only that recording and returns a verdict, and you send the take through the -submission form for your pull request. This page explains the process, the hand suite and what a -verdict means. +You have integrated a device that publishes hand or full-body poses into Isaac Capture. The +Conformance Test Suite (CTS) produces the evidence that the integration works: you record one +scripted take, a checker reads only that recording and returns a verdict, and you send the take +through the submission form for your pull request. This page explains the process, the two suites +and what a verdict means. How it works ------------ @@ -22,8 +22,8 @@ How it works :link: /device/add_device :link-type: doc - Your device feeds Isaac Capture's hand tracker, through your plugin or the headset's own - tracking. + Your device feeds Isaac Capture's hand or body tracker, through your plugin or the + headset's own tracking. +++ Add a New Device @@ -39,19 +39,19 @@ How it works Practice the script until the performer knows every step. +++ - :ref:`Hand suite ` + :ref:`Hand ` · :ref:`Full body ` .. grid-item-card:: 4 · Record Record one scripted take in the capture panel in your browser. +++ - :ref:`Hand suite ` + :ref:`Hand ` · :ref:`Full body ` .. grid-item-card:: 5 · Check The checker reads the take and returns one verdict. +++ - :ref:`Hand suite ` + :ref:`Hand ` · :ref:`Full body ` .. grid-item-card:: 6 · Submit :link: submit @@ -63,8 +63,10 @@ How it works .. _cts-overview-suites: -The hand suite --------------- +Pick your suite +--------------- + +Run the suite for the data your device produces. A device that produces both runs both. .. grid:: 1 1 2 2 :gutter: 3 @@ -80,6 +82,17 @@ The hand suite +++ Hand Suite + .. grid-item-card:: Full body + :link: full_body + :link-type: doc + + - **For:** headset body tracking, or a mocap suit through a vendor backend + - **Records:** ``core.FullBodyPoseRecord``, 24 joints + - **Script:** 10 poses and motions, standing + - **Pacing:** self-paced; you press when ready, then hold the pose or do the motion + +++ + Full-Body Suite + What the checker looks at ------------------------- @@ -95,20 +108,20 @@ What the checker looks at - Finite values, unit quaternions, monotonic timestamps, frame rate and gaps, joint speed * - Skeleton geometry - Is it a plausible human skeleton, in metres? - - Units, bone lengths that stay constant, human proportions, joints in their named slots, - handedness + - Units, bone lengths that stay constant, human proportions, joints in their named slots + and on their named sides, handedness * - Placement and frames - Are the joints where the body is, in the frame they claim? - Not parked at the origin, wrist not frozen, quaternion component order, positions and - orientations that agree + orientations that agree, +Y up * - Poses over the scripted steps - Did each step happen, in order, as labelled? - - Hands flat on a level table, fist closure, pinch finger identity, palms together, - fingertip contact through the rolls + - Hands flat on a level table, pinch finger identity, arm raised overhead, squat depth, + march rhythm The checker needs only the ``mcap`` and ``flatbuffers`` Python packages. It is deterministic, so we re-run it on your take and get the same verdict. Some checks are only measured and reported; -the suite page says which. +the suite pages say which. .. _cts-overview-verdicts: @@ -172,7 +185,8 @@ What you need - Your device's plugin built and installed, if it has one. - ``aplay`` (``alsa-utils``) for the spoken cues. Without it, or without speakers, the capture panel's on-screen cues still guide every step. -- A table and a chair for the script, and ideally a second person at the screen. +- Room for the script (a table and chair for hand, standing space for full body), and ideally a + second person at the screen. - A Google account to sign in to the submission form. Start with :doc:`setup`. @@ -184,4 +198,5 @@ Start with :doc:`setup`. setup hand + full_body submit diff --git a/docs/source/conformance/setup.rst b/docs/source/conformance/setup.rst index 70083d3ed8..c4883b73a2 100644 --- a/docs/source/conformance/setup.rst +++ b/docs/source/conformance/setup.rst @@ -7,8 +7,8 @@ Set Up the Tools ================ This page gets a workstation ready to record: the repository built, the CTS tool environments -created and a headset streaming through CloudXR. Do it once per clone. Run the commands from the -repository root. +created and a headset streaming through CloudXR. Do it once per clone; both suites share every step. +Run the commands from the repository root. .. contents:: Steps :local: @@ -47,9 +47,10 @@ repository root. * - Your plugin, installed - ``cmake --install build`` installs every built plugin into ``install/plugins/``; add ``--component `` to install one, if its plugin declares a component. Headset hand - tracking needs no plugin. + tracking and PICO body tracking need no plugin. * - Space and a helper - - A table and a chair. A second person at the screen makes the take easier. + - Hand: a table and a chair. Full body: room to stand, raise both arms and squat. A second + person at the screen makes either suite easier. 2. Build the repository ----------------------- @@ -72,14 +73,15 @@ A plugin behind a ``BUILD_PLUGIN_`` option builds only when you add 3. Create the tool environments ------------------------------- -The suite has a checker environment and a capture environment. This line sets up the checker -first, because the capture environment reads recordings through the bindings the checker -generates: +Each suite has a checker environment and a capture environment. Run the line for each suite you +need; it sets up the checker first, because the capture environment reads recordings through the +bindings the checker generates: .. code-block:: bash CTS=src/python/isaaccapture/cts $CTS/hand/checker/setup_env.sh --panel && $CTS/hand/capture/setup_env.sh + $CTS/full_body/checker/setup_env.sh --panel && $CTS/full_body/capture/setup_env.sh ``--panel`` adds the viewer, which replays a take and packages it for submission. To only check takes on another machine, such as a Mac, run the checker script alone there. The scripts are @@ -91,12 +93,13 @@ idempotent and write only inside their own directory; re-run them after pulling ---------------------- CloudXR is the OpenXR runtime the capture runs on. **Start recording** waits until a headset has -connected, even when your device produces the joints. Use the capture interpreter, and set ``PY`` -in each terminal you open: +connected, even when your device produces the joints. Use the capture interpreter of either suite, +and set ``PY`` in each terminal you open: .. code-block:: bash PY=$PWD/src/python/isaaccapture/cts/hand/capture/.venv/bin/python + # or …/cts/full_body/capture/.venv/bin/python #. Start the CloudXR service in a terminal of its own and leave it open. The first time, it shows a link to the CloudXR licence and asks you to accept it; your acceptance is remembered. @@ -132,7 +135,8 @@ in each terminal you open: The workstation firewall must allow the CloudXR ports (:ref:`whitelist-firewall-ports`). For device profiles, a detached service or opening the client over USB, see -:doc:`/references/cloudxr`. +:doc:`/references/cloudxr`. For PICO body tracking, set up the trackers first: +:doc:`/device/body_tracking/index`. Troubleshooting --------------- @@ -162,4 +166,4 @@ Troubleshooting - One is already running. ``$PY -m isaaccapture.cloudxr.service status`` reports it; ``service stop`` ends a detached one, Ctrl+C a foreground one. -Next, record a take: :doc:`hand`. +Next, record a take: :doc:`hand` or :doc:`full_body`. diff --git a/docs/source/conformance/submit.rst b/docs/source/conformance/submit.rst index 965767fde7..0306d5b5b7 100644 --- a/docs/source/conformance/submit.rst +++ b/docs/source/conformance/submit.rst @@ -20,31 +20,36 @@ integration pull request. You can submit any verdict, as long as its report goes Open the pull request that adds your device (:doc:`/device/add_device`, :doc:`/development/contributing`). Each form submission refers to that pull request. -2. Record and check a take --------------------------- +2. Record and check one take per suite +-------------------------------------- -Record and check a take with the :doc:`hand`. Takes are never overwritten, so submit the one you -want reviewed. Record from a commit you have pushed to the pull request, with nothing under -``src/python/isaaccapture/cts/`` changed. The +Record and check one take for each suite your device supports: :doc:`hand`, :doc:`full_body`, or +both. Takes are never overwritten, so submit the one you want reviewed. Record from a commit you +have pushed to the pull request, with nothing under ``src/python/isaaccapture/cts/`` changed. The take records the commit it was recorded at, and the report whether the checker's code was modified; we re-run the checker at that commit. 3. Package the take ------------------- -Keep the four files of the take together and never rename them. Open the take in the viewer: +Keep the four files of the take together and never rename them. Open the take in the viewer of +its suite: .. code-block:: bash + # Hand src/python/isaaccapture/cts/hand/checker/.venv/bin/python -m hand_cts.panel \ ~/isaaccapture-cts//-hand.mcap + # Full body + src/python/isaaccapture/cts/full_body/checker/.venv/bin/python -m full_body_cts.panel \ + ~/isaaccapture-cts//-body.mcap The viewer serves port 8080, or the next free port; open the address it prints and press **package for submission** in the **Submission** folder. When the archive is ready, a -notification in the viewer offers ``-hand..zip`` with its size. Click it to save -the archive on the computer running the browser, or right-click it and choose **Save link as** -to pick where. Under the button, the viewer shows the archive's name, size and the first 12 -characters of its SHA-256; you quote them in step 5. +notification in the viewer offers ``-hand..zip`` or ``-body..zip`` +with its size. Click it to save the archive on the computer running the browser, or right-click it +and choose **Save link as** to pick where. Under the button, the viewer shows the archive's name, +size and the first 12 characters of its SHA-256; you quote them in step 5. .. code-block:: text @@ -71,7 +76,7 @@ Submit the form once for each archive. The form asks you to sign in with a Googl 5. Describe the take in your pull request ----------------------------------------- -Add this block to the pull request description: +Add one block per suite to the pull request description: .. code-block:: text diff --git a/docs/source/device/add_device.rst b/docs/source/device/add_device.rst index d5be9b5da4..728e968db6 100644 --- a/docs/source/device/add_device.rst +++ b/docs/source/device/add_device.rst @@ -290,4 +290,4 @@ For the shared library build and contribution workflow, see .. seealso:: - Once your device publishes hand poses, prove it with :doc:`/conformance/overview`. + Once your device publishes hand or full-body poses, prove it with :doc:`/conformance/overview`. diff --git a/docs/tools/cts_media/README.md b/docs/tools/cts_media/README.md index 157cd7a545..ce422fac11 100644 --- a/docs/tools/cts_media/README.md +++ b/docs/tools/cts_media/README.md @@ -7,21 +7,23 @@ SPDX-License-Identifier: Apache-2.0 Generates the step GIFs and the hand rehearsal track used by the Device Conformance pages (`docs/source/conformance/`). The outputs are committed; nothing here runs in CI. -Re-run it, and commit the outputs with the change, when the hand `capture/session.py` +Re-run it, and commit the outputs with the change, when a suite's `capture/session.py` (`STEPS`, `COUNTDOWN_BEATS`, `BEAT_S`), the hand `capture_panel.py` `TAIL_S`, the hand -cue WAVs or the oracle's motion changes. +cue WAVs or an oracle's motion changes. | Output | Made by | |---|---| | `docs/source/_static/cts/hand/NN-