Skip to content

OpenUSD: the OPC UA to OpenUSD binding, scene materialization and connector - #4126

Merged
marcschier merged 3 commits into
marcschier/3827-3-positioningfrom
marcschier/3827-4-openusd
Aug 1, 2026
Merged

OpenUSD: the OPC UA to OpenUSD binding, scene materialization and connector#4126
marcschier merged 3 commits into
marcschier/3827-3-positioningfrom
marcschier/3827-4-openusd

Conversation

@marcschier

Copy link
Copy Markdown
Collaborator

Stack 4/5 — base #4125. Part of the #4096 split; see #4096 for the overall picture.

Review after #4123, #4124 and #4125.

What this is

The generic OPC UA to OpenUSD binding, scene materialization, and the connector that drives a live stage from a running server.

Contents

Binding (Part 1)Opc.Ua.OpenUsd and Opc.Ua.OpenUsd.Server. A server describes how its Variables drive USD prims, and serves the USD layers it refers to as Part 5 files with a content digest.

Scene materialization (Part 2)Opc.Ua.OpenUsdScene and Opc.Ua.OpenUsdScene.Server, including the USDA writer.

  • Escaping fix: string values, composition-arc references, variant set names and selections, doc and prim names were all emitted unescaped, so a value carrying a quote or a newline could author its own layer syntax. Every emit site now goes through the escapers. The tests assert the right property — not that the payload is absent (it legitimately survives inside the escaped literal) but that no payload becomes its own line of layer syntax.

ClientOpc.Ua.OpenUsd.Client streams live values into an IUsdSink. CompositeUsdSink fans out to several sinks; the file sink interpolates between server samples so motion is continuous rather than stepped at the publishing interval.

Connectortools/Opc.Ua.OpenUsd.Connector composes a stage from a live server. The optional in-process viewport lives in a separate assembly probed at run time, so the connector still runs — and says why — when it is absent.

  • Fix: the asset cache and PKI root moved off the shared temp directory to LocalApplicationData.

SamplePumpDeviceIntegrationServer gains an OpenUSD representation of the pump.

Notes for the reviewer

  • The viewport assembly is net10.0-only. It is what exercises the Directory.Build.targets change from 1/5: without it, the net8.0 leg of the per-TFM CI build fails with CS0433 because the System.Threading.Lock polyfill collides with the real type.
  • UsdAssetDelivery hashes through SHA256.Create rather than the static HashData, which does not exist on the net472/net48 targets this test project also builds for.

Validation

dotnet build UA.slnx — 0 errors, 0 warnings.

Suite Result
Opc.Ua.OpenUsd.Tests 621 / 0
Opc.Ua.Di.Tests 321 / 0

@marcschier
marcschier marked this pull request as draft July 30, 2026 14:03
@marcschier
marcschier marked this pull request as ready for review July 30, 2026 17:25
Copilot AI review requested due to automatic review settings July 30, 2026 17:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.46150% with 608 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.04%. Comparing base (91f79b7) to head (8c19c10).

Files with missing lines Patch % Lines
src/Opc.Ua.OpenUsdScene/Conversion/UsdaReader.cs 81.06% 87 Missing and 88 partials ⚠️
...Opc.Ua.OpenUsdScene/Conversion/UsdValueCoercion.cs 45.29% 105 Missing and 17 partials ⚠️
src/Opc.Ua.OpenUsdScene/Conversion/UsdaWriter.cs 75.33% 51 Missing and 23 partials ⚠️
src/Opc.Ua.OpenUsd.Client/OpenUsdConnector.cs 91.13% 32 Missing and 38 partials ⚠️
....Ua.OpenUsd.Client/OpenUsdConnector.Composition.cs 69.14% 41 Missing and 17 partials ⚠️
...pc.Ua.OpenUsdScene/Conversion/UsdSceneSignature.cs 76.40% 15 Missing and 6 partials ⚠️
src/Opc.Ua.OpenUsdScene.Server/UsdSceneExporter.cs 90.04% 0 Missing and 20 partials ⚠️
src/Opc.Ua.OpenUsd.Server/UsdAssetDelivery.cs 89.89% 1 Missing and 9 partials ⚠️
...Opc.Ua.OpenUsdScene.Server/UsdSceneMaterializer.cs 95.23% 3 Missing and 4 partials ⚠️
...c/Opc.Ua.OpenUsd.Client/OpenUsdConnector.Assets.cs 95.68% 3 Missing and 3 partials ⚠️
... and 15 more
Additional details and impacted files

Impacted file tree graph

@@                        Coverage Diff                         @@
##           marcschier/3827-3-positioning    #4126       +/-   ##
==================================================================
+ Coverage                          68.93%   80.04%   +11.10%     
==================================================================
  Files                               1454     1574      +120     
  Lines                             202675   217825    +15150     
  Branches                           35125    37779     +2654     
==================================================================
+ Hits                              139713   174354    +34641     
+ Misses                             51178    30372    -20806     
- Partials                           11784    13099     +1315     
Files with missing lines Coverage Δ
src/Opc.Ua.OpenUsd.Client/CompositeUsdSink.cs 100.00% <100.00%> (ø)
...c/Opc.Ua.OpenUsd.Client/OpenUsdConnectorOptions.cs 100.00% <100.00%> (ø)
src/Opc.Ua.OpenUsdScene/Scene/UsdCompositionArc.cs 100.00% <100.00%> (ø)
...c/Opc.Ua.OpenUsd.Client/OpenUsdConnectorFactory.cs 85.71% <85.71%> (ø)
src/Opc.Ua.OpenUsdScene/Scene/UsdRelationship.cs 50.00% <50.00%> (ø)
src/Opc.Ua.OpenUsd.Client/MockUsdSink.cs 92.30% <92.30%> (ø)
...rc/Opc.Ua.OpenUsdScene.Server/UsdSceneDiscovery.cs 98.09% <98.09%> (ø)
src/Opc.Ua.OpenUsdScene/Scene/UsdApiSchema.cs 66.66% <66.66%> (ø)
src/Opc.Ua.OpenUsdScene/Scene/UsdAttribute.cs 66.66% <66.66%> (ø)
src/Opc.Ua.OpenUsdScene/Scene/UsdVariantSet.cs 33.33% <33.33%> (ø)
... and 18 more

... and 510 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread Directory.Packages.props
Comment thread src/Opc.Ua.OpenUsdScene/Scene/UsdAttribute.cs
@marcschier marcschier added the ready Ready to merge once CI Passes label Jul 31, 2026
…nector

Fourth in the #4096 stack, on top of the positioning change.

- Opc.Ua.OpenUsd and Opc.Ua.OpenUsd.Server carry the binding model: a server
  describes how its Variables drive USD prims, and serves the USD layers it
  refers to as Part 5 files with a content digest.
- Opc.Ua.OpenUsdScene and Opc.Ua.OpenUsdScene.Server carry scene
  materialization, including the USDA writer. String values, composition arc
  references, variant set names and selections, doc and prim names are all
  escaped now; without that a value carrying a quote or a newline could author
  its own layer syntax.
- Opc.Ua.OpenUsd.Client streams live values into an IUsdSink. CompositeUsdSink
  fans out to several sinks and the file sink interpolates between server
  samples so motion is continuous rather than stepped at the publishing
  interval.
- tools/Opc.Ua.OpenUsd.Connector composes a stage from a live server. Its
  optional in-process viewport lives in a separate assembly probed at run time,
  so the connector still runs, and says why, when it is absent. Its asset cache
  and PKI root moved off the shared temp directory to the local application
  data directory.
- PumpDeviceIntegrationServer gains an OpenUSD representation of the pump.

The Opc.Ua.OpenUsd.Tests suite is 621 tests. UsdAssetDelivery hashes through
SHA256.Create rather than the static HashData, which does not exist on the
net472 and net48 targets this test project also builds for.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8cbb8cd0-f0cb-4ab0-bea2-6202fbf69485
@marcschier
marcschier force-pushed the marcschier/3827-4-openusd branch from f10ecaf to 99dcb6d Compare July 31, 2026 12:01
…bally

Clearing <packageSources> does not re-enable a source that a user or machine
level NuGet.config has disabled, so a checkout on a machine that disables
nuget.org (common where a corporate feed proxy is configured) ends up with no
usable feed at all. Restore then fails for any package that is not already in
the global packages folder, which is why only newly introduced packages such as
the OpenUSD ones surfaced the problem while everything else restored from cache.

Clear <disabledPackageSources> as well so the feed declared here is the one that
is actually used.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8cbb8cd0-f0cb-4ab0-bea2-6202fbf69485
@marcschier
marcschier merged commit fb160a8 into master Aug 1, 2026
178 of 180 checks passed
marcschier added a commit that referenced this pull request Aug 1, 2026
#4127)

**Stack 5/5** — base #4126. Part of the #4096 split; see #4096 for the
overall picture. Closes the API work for #3827.

> Review after #4123, #4124, #4125 and #4126. This branch is
content-identical to the original #4096 branch, so merging the stack
lands exactly what #4096 contained.

## The problem this solves

OPC 40010 1.02 defines a rich robot **topology** but **no motion verbs
at all** — its actuation surface is the SystemOperation and TaskControl
state machines plus a Controller `Programs` directory. Meanwhile
[URML](https://github.com/URML-MARS/URML) names OPC UA Robotics as its
canonical non-ROS substrate and asks for `MoveTo` / `Grasp` / `Release`
methods the companion spec does not define, so today it needs a
hand-maintained per-deployment NodeId mapping file.

This closes that gap in two clearly separated tiers, and never presents
the second as standard.

## Contents

**Server** — stock `RoboticsNodeManager`, ordered
`IRoboticsModelProvider` composition, `IRoboticsConfigurator`
code-behind, and validated fluent topology builders for systems,
controllers, motion devices, axes, power trains, motors, gears, drives,
safety states, software, task controls and task modules, with the
correct OPC 40010 semantic references.

**Standard operations** — `AddSystemOperation` and
`AddTaskControlOperation` drive the Part 16 state machines. An illegal
cause is rejected with `BadInvalidState` before the handler runs; a
handler returning a bad `ServiceResult` does not move the machine; and a
transition already in flight rejects a concurrent one rather than
letting both commit.

**Programs** — binds the optional `FileDirectoryType` through the
reusable `IFileDirectoryBinder` added in 1/5.

**Operation conventions** — opt-in and explicitly non-normative `MoveTo`
/ `MoveJ` / `MoveL` / `Grasp` / `Release` / `PickFrom` / `PlaceAt` /
`SwapTool` / `SetOutput` / `CallProgram`, created **only** in an
application-owned namespace — the OPC UA, DI, IA and Robotics namespaces
are rejected — plus a generic `AddOperation<TRequest, TResponse>`
extension point.

**Client** — `RoboticsClient` extends the DI client, is subtype aware
throughout, and provides typed topology snapshots, the standard
operation and task-control clients, `ProgramsAsync`, streaming
observation and a DI factory. Verbs resolve by BrowseName, so no NodeId
mapping file is needed.

**Sample** — `MinimalRobotServer` composes five models (Robotics, IA,
DI, OpenUSD, RSL/GPOS) purely through `IRoboticsModelProvider`
contributions, which is the real proof that the stock hosting is
sufficient. It follows the published KUKA KR 16-2 kinematics and axis
limits with an eased pick-and-place cycle.

Also restores the vendor-subtype scanner test held back from 2/5, which
uses the Robotics NodeSet as its fixture.

## Defects found and fixed along the way

- **`ControllerType.CurrentUser`** is Mandatory in OPC 40010 but was
neither built nor validated. Now has a builder and a validation error.
- **`MotionDeviceType.TaskControlReference`** was absent because it must
target a `TaskControlOperationType` instance that did not exist. Now
wired.

## Validation

`dotnet build UA.slnx` — 0 errors, 0 warnings.

| Suite | Result |
| --- | --- |
| Opc.Ua.Robotics.Tests | 103 / 0 |
| Opc.Ua.OpenUsd.Tests | 635 / 0 |
| Opc.Ua.Di.Tests | 342 / 0 |
| Opc.Ua.SourceGeneration.Tests | 94 / 0 |
| Opc.Ua.Aot.Tests (NativeAOT) | 120 / 0 |

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8cbb8cd0-f0cb-4ab0-bea2-6202fbf69485
@marcschier
marcschier deleted the marcschier/3827-4-openusd branch August 1, 2026 05:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready Ready to merge once CI Passes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants