Skip to content

Positioning: OPC 10000-210 RSL and 10000-211 GPOS on one geolocation provider - #4125

Merged
marcschier merged 4 commits into
marcschier/3827-2-source-generatorfrom
marcschier/3827-3-positioning
Aug 1, 2026
Merged

marcschier merged 4 commits into
marcschier/3827-2-source-generatorfrom
marcschier/3827-3-positioning

Conversation

@marcschier

Copy link
Copy Markdown
Collaborator

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

Review after #4123 and #4124.

What this is

The OPC 10000-210 Relative Spatial Location and OPC 10000-211 Global Positioning companion models, with their server and client libraries, plus the ISA-95 migration onto the shared geolocation seam.

Why it is one change

A deployment writes one provider implementation and both OPC 10000-211 and OPC 10030 are served from it. The specifications disagree on representation, not on content:

  • GPOS publishes the structured GlobalLocationDataType and validates the EPSG code against the configured CRS.
  • ISA-95 publishes the same sample as the String array that OPC 10030 §8.3.2.2 requires.

Splitting them would mean two provider interfaces for one physical sensor, which is exactly what this avoids. The seam itself lives in Opc.Ua.Server and landed in 1/5.

Contents

  • Opc.Ua.Positioning, .Server and .Client.
  • Opc.Ua.ISA95.Server moves onto IGeoLocationProvider; the three ISA-95-specific provider files are removed because the shared seam and its in-memory implementation replace them.
  • Fixes a conformance gap: the ISA-95 binder wrote a scalar where the type declares ValueRank OneOrMoreDimensions. It now writes String[].
  • Fixes a liveness bug: a provider that cannot push is polled at the Variable's MinimumSamplingInterval rather than installed once, so a non-pushing provider no longer serves its start-up sample with Good status forever.
  • samples/MinimalIsa95Server.

Validation

dotnet build UA.slnx — 0 errors.

Suite Result
Opc.Ua.Positioning.Tests 69 / 0
Opc.Ua.ISA95.Tests 136 / 0
Opc.Ua.Di.Tests 304 / 0

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.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Adds the OPC UA Positioning stack (RSL 10000-210 + GPOS 10000-211) and migrates ISA-95 GeoSpatialLocation onto the shared IGeoLocationProvider seam so one provider can back both structured (GPOS) and textual (ISA-95) representations.

Changes:

  • Introduces new Opc.Ua.Positioning base library plus ...Server and ...Client packages, including transforms, hosting, and typed client operations.
  • Migrates ISA-95 GeoSpatialLocation binding and tests from the ISA-95-specific provider to the shared IGeoLocationProvider (+ formatter projection to String[] literals).
  • Adds comprehensive new test project for positioning and updates docs/solution metadata to include the new packages.

Reviewed changes

Copilot reviewed 69 out of 70 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/Opc.Ua.Positioning.Tests/Transforms/Wgs84TransformTests.cs Adds transform golden/round-trip tests for WGS84 ECEF/ENU conversions.
tests/Opc.Ua.Positioning.Tests/Transforms/TransformTestHelpers.cs Shared helpers for transform tests.
tests/Opc.Ua.Positioning.Tests/Transforms/RslFrameTransformTests.cs Adds extensive tests for RSL frame conventions, composition, inversion, and gimbal lock.
tests/Opc.Ua.Positioning.Tests/Transforms/InternalMathTests.cs Adds tests for internal matrix/vector helper types.
tests/Opc.Ua.Positioning.Tests/PositioningServerFixture.cs Test fixture for hosting a positioning node manager in-process.
tests/Opc.Ua.Positioning.Tests/PositioningHostingTests.cs Tests DI/hosting registration for positioning server/client.
tests/Opc.Ua.Positioning.Tests/PositioningAddressSpaceBuilderTests.cs Tests address-space builder creates RSL/GPOS nodes and validates inputs.
tests/Opc.Ua.Positioning.Tests/Opc.Ua.Positioning.Tests.csproj New test project for positioning.
tests/Opc.Ua.Positioning.Tests/ModelGenerationTests.cs Validates generated namespaces/NodeIds and loader/factory behavior.
tests/Opc.Ua.Positioning.Tests/ModelEncodingTests.cs Validates binary/JSON encoding round-trips for GPOS types.
tests/Opc.Ua.ISA95.Tests/Integration/Isa95EndToEndTests.cs Updates end-to-end ISA-95 test to use shared provider and String[] literal value.
tests/Opc.Ua.ISA95.Tests/Common/Isa95GeoSpatialLocationTests.cs Reworks ISA-95 location tests for shared provider, sourceId, and String[] literals.
src/Opc.Ua.Types/Utils/ValueGuards.cs Adds cross-target guard helpers used by transforms.
src/Opc.Ua.Positioning/Transforms/Wgs84CoordinateReferenceSystemTransformer.cs Adds built-in EPSG:4326 CRS transformer for geodetic <-> ECEF conversion.
src/Opc.Ua.Positioning/Transforms/Vector3.cs Adds internal immutable vector used by transforms.
src/Opc.Ua.Positioning/Transforms/SmallLinearAlgebra.cs Adds small-matrix linear algebra (SVD, inversion) used for fitting.
src/Opc.Ua.Positioning/Transforms/RslFrameTransform.cs Implements RSL Annex B frame transform (compose/invert/convert).
src/Opc.Ua.Positioning/Transforms/Matrix3x3.cs Adds internal immutable matrix used by transforms.
src/Opc.Ua.Positioning/Transforms/LocalTangentPlane.cs Implements ENU tangent plane projections for a CRS.
src/Opc.Ua.Positioning/Transforms/ICoordinateReferenceSystemTransformer.cs Defines CRS transformation extension point.
src/Opc.Ua.Positioning/Transforms/GroundControlPointFitResult.cs Exposes fitted zone transform + diagnostics and mapping helpers.
src/Opc.Ua.Positioning/Transforms/GroundControlPointFitOptions.cs Adds options for fitting, including CRS selection.
src/Opc.Ua.Positioning/Transforms/GroundControlPointFitMode.cs Defines fit modes (rigid/similarity/affine).
src/Opc.Ua.Positioning/Transforms/GeographicCoordinates.cs Helpers for elevation encoding-mask semantics.
src/Opc.Ua.Positioning/Transforms/AngleUnit.cs Adds explicit radians/degrees angle unit enum.
src/Opc.Ua.Positioning/Transforms/AngleMath.cs Adds angle conversion helpers used by transforms.
src/Opc.Ua.Positioning/Properties/AssemblyInfo.cs Assembly metadata tweak for positioning library.
src/Opc.Ua.Positioning/Opc.Ua.Positioning.csproj New positioning model+transform project with source generation inputs.
src/Opc.Ua.Positioning/NugetREADME.md Package README for positioning base library.
src/Opc.Ua.Positioning/Model/Opc.Ua.RSL.NodeSet2.csv Adds RSL NodeId mapping inputs for generator.
src/Opc.Ua.Positioning/Model/Opc.Ua.GPOS.NodeSet2.csv Adds GPOS NodeId mapping inputs for generator.
src/Opc.Ua.Positioning.Server/Providers/IRelativeSpatialLocationProvider.cs Adds relative provider contract + sample type.
src/Opc.Ua.Positioning.Server/Properties/AssemblyInfo.cs Assembly metadata tweak for positioning server.
src/Opc.Ua.Positioning.Server/PositioningProviderSubscription.cs Adds disposable owner for provider watch loops.
src/Opc.Ua.Positioning.Server/PositioningNodeManagerFactory.cs Adds node manager factory advertising both namespaces.
src/Opc.Ua.Positioning.Server/PositioningNodeManager.cs Implements standalone node manager loading RSL+GPOS and metadata ensure.
src/Opc.Ua.Positioning.Server/Opc.Ua.Positioning.Server.csproj New positioning server package project.
src/Opc.Ua.Positioning.Server/NugetREADME.md Package README for positioning server.
src/Opc.Ua.Positioning.Server/Hosting/PositioningPostSetup.cs Adds post-setup runner/context + namespace metadata attachment.
src/Opc.Ua.Positioning.Server/Hosting/OpcUaPositioningServerBuilderExtensions.cs Adds DI hosting extensions for standalone/composed server integration.
src/Opc.Ua.Positioning.Server/Hosting/IPositioningServerBuilder.cs Defines fluent registration surface for providers.
src/Opc.Ua.Positioning.Server/EventIds.cs Adds event IDs for positioning server logging.
src/Opc.Ua.Positioning.Client/Properties/AssemblyInfo.cs Assembly metadata tweak for positioning client.
src/Opc.Ua.Positioning.Client/PositioningEntries.cs Adds typed client DTOs/records for discovered objects and values.
src/Opc.Ua.Positioning.Client/PositioningClientOperations.cs Adds internal client helpers for browse/translate/read.
src/Opc.Ua.Positioning.Client/Opc.Ua.Positioning.Client.csproj New positioning client package project.
src/Opc.Ua.Positioning.Client/NugetREADME.md Package README for positioning client.
src/Opc.Ua.Positioning.Client/Hosting/OpcUaPositioningClientBuilderExtensions.cs Adds DI registration for managed-session client factories.
src/Opc.Ua.Positioning.Client/GlobalPositioningClient.cs Implements high-level GPOS client with reads and streaming observers.
src/Opc.Ua.ISA95.Server/Providers/Isa95GeoSpatialLocationServiceCollectionExtensions.cs Removes ISA-95-specific DI provider registration (replaced by shared seam).
src/Opc.Ua.ISA95.Server/Providers/Isa95GeoSpatialLocationProvider.cs Removes ISA-95-specific in-memory provider (replaced by shared in-memory provider).
src/Opc.Ua.ISA95.Server/Providers/IIsa95GeoSpatialLocationProvider.cs Removes ISA-95-specific provider interface/types (replaced by IGeoLocationProvider).
src/Opc.Ua.ISA95.Server/Builders/Isa95ModelBuilder.cs Switches GeoSpatialLocation creation/binding to shared provider, sourceId, formatter.
src/Opc.Ua.ISA95.Server/Builders/Isa95GeoSpatialLocationBinder.cs Reworks binder to project shared samples into ISA-95 String[] literals w/ push support.
src/Opc.Ua.ISA95.Server/Builders/IIsa95ModelBuilder.cs Updates interface to shared provider + sourceId + formatter parameters.
samples/MinimalIsa95Server/README.md Updates sample docs to shared provider + WKT projection.
samples/MinimalIsa95Server/Program.cs Updates sample to seed shared provider and pass sourceId to builder.
docs/Positioning.md Adds developer documentation for packages, server hosting, providers, clients, transforms.
docs/ISA95.md Updates ISA-95 docs to shared seam, String[] semantics, and new example.
UA.slnx Includes new positioning projects and test project in solution.
.gitattributes Marks NodeSet CSV/XML as binary to preserve byte-for-byte artifacts.
Comments suppressed due to low confidence (4)

src/Opc.Ua.ISA95.Server/Builders/Isa95GeoSpatialLocationBinder.cs:1

  • GeoSpatialLocationType is documented (and tested) as ValueRank=OneOrMoreDimensions, so writing Variant.Null reintroduces a type-shape mismatch (null variant vs. String[]). Prefer returning an explicitly typed empty string array (e.g., new Variant(ArrayOf<string>.Empty) or an ArrayOf<string> with Count==0) when there are no literals, and use StatusCode to convey “no data” if needed.
/* ========================================================================

src/Opc.Ua.Positioning/Transforms/GroundControlPointFitResult.cs:1

  • Span<double> source = [ ... ] (and the similar target = [ ... ] below) may allocate a temporary array depending on compiler/language version and target frameworks. Since this is hot-path numeric code, use stackalloc (or direct locals) for these fixed-size buffers to ensure allocation-free execution across targets.
    src/Opc.Ua.Positioning/Transforms/LocalTangentPlane.cs:1
  • Origin stores the caller-provided S3DGeographicCoordinateDataType reference directly. Since these UA data types are mutable, external mutation after construction would make Origin inconsistent with the already-computed m_originEcef/rotation matrices. Consider copying/cloning origin into a new instance for Origin (or documenting that the input must not be mutated after construction).
    src/Opc.Ua.Positioning/Transforms/SmallLinearAlgebra.cs:1
  • The implementation assumes n is 2 or 3, but will throw IndexOutOfRangeException (or silently compute nonsense) for other sizes, despite being a public utility within the assembly. Add explicit dimension validation (including checking a.GetLength(0) == a.GetLength(1) and n == 2 || n == 3) and throw ArgumentException with a clear message to make failures deterministic and easier to diagnose.

Comment thread src/Opc.Ua.Positioning.Client/PositioningClientOperations.cs
marcschier added a commit that referenced this pull request Jul 30, 2026
…thing

Review feedback on #4125. ArrayOf<T> implements INullable, so `default` is
the null array, which is a different thing on the wire from an empty one.
Browsing for children that do not exist means ''no children'', not ''value not
present'', so BrowseChildrenAsync now returns ArrayOf<ReferenceDescription>.Empty.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8cbb8cd0-f0cb-4ab0-bea2-6202fbf69485
@codecov

codecov Bot commented Jul 31, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 73.74732% with 613 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.91%. Comparing base (f69d7a3) to head (91f79b7).

Files with missing lines Patch % Lines
...sitioning.Server/PositioningAddressSpaceBuilder.cs 75.93% 155 Missing and 50 partials ⚠️
...ositioning.Client/RelativeSpatialLocationClient.cs 32.24% 143 Missing and 2 partials ⚠️
...c.Ua.Positioning.Client/GlobalPositioningClient.cs 49.09% 112 Missing and 1 partial ⚠️
...Positioning/Transforms/GroundControlPointFitter.cs 83.82% 19 Missing and 19 partials ⚠️
....Positioning.Client/PositioningClientOperations.cs 70.17% 25 Missing and 9 partials ⚠️
...Opc.Ua.Positioning/Transforms/RslFrameTransform.cs 85.71% 10 Missing and 1 partial ⚠️
...pc.Ua.Positioning/Transforms/SmallLinearAlgebra.cs 93.37% 4 Missing and 6 partials ⚠️
...Hosting/OpcUaPositioningClientBuilderExtensions.cs 76.47% 6 Missing and 2 partials ⚠️
src/Opc.Ua.Positioning/Transforms/Matrix3x3.cs 84.31% 7 Missing and 1 partial ⚠️
...5.Server/Builders/Isa95GeoSpatialLocationBinder.cs 82.35% 3 Missing and 3 partials ⚠️
... and 11 more

❌ Your patch check has failed because the patch coverage (73.74%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@                          Coverage Diff                           @@
##           marcschier/3827-2-source-generator    #4125      +/-   ##
======================================================================
- Coverage                               79.98%   79.91%   -0.07%     
======================================================================
  Files                                    1527     1546      +19     
  Lines                                  211445   213643    +2198     
  Branches                                36495    36739     +244     
======================================================================
+ Hits                                   169118   170739    +1621     
- Misses                                  29566    30049     +483     
- Partials                                12761    12855      +94     
Files with missing lines Coverage Δ
.../Opc.Ua.ISA95.Server/Builders/Isa95ModelBuilder.cs 84.61% <100.00%> (+0.34%) ⬆️
...Ua.Positioning/Transforms/GeographicCoordinates.cs 100.00% <100.00%> (ø)
...Opc.Ua.Positioning/Transforms/LocalTangentPlane.cs 100.00% <100.00%> (ø)
src/Opc.Ua.Positioning/Transforms/AngleMath.cs 50.00% <50.00%> (ø)
src/Opc.Ua.Types/Utils/ValueGuards.cs 50.00% <50.00%> (ø)
...Positioning.Server/Hosting/PositioningPostSetup.cs 97.64% <97.64%> (ø)
src/Opc.Ua.Positioning/Transforms/Vector3.cs 91.66% <91.66%> (ø)
...ositioning.Server/PositioningNodeManagerFactory.cs 72.72% <72.72%> (ø)
...itioning.Server/PositioningProviderSubscription.cs 75.00% <75.00%> (ø)
...itioning/Transforms/GroundControlPointFitResult.cs 92.10% <92.10%> (ø)
... and 14 more

... and 19 files with indirect coverage changes

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

@marcschier marcschier added the ready Ready to merge once CI Passes label Jul 31, 2026
marcschier and others added 3 commits July 31, 2026 13:18
… provider

Third in the #4096 stack, on top of the source generator change.

Adds the Relative Spatial Location and Global Positioning companion models with
their server and client libraries, and migrates ISA-95 onto the
IGeoLocationProvider seam introduced by the core stack change at the bottom of
this stack. A deployment writes one provider and both OPC 10000-211 and
OPC 10030 are served from it: the specifications disagree on representation,
not on content, so the difference is handled as a projection.

- GPOS publishes the structured GlobalLocationDataType and validates the EPSG
  code against the configured CRS.
- ISA-95 publishes the same sample as the String array that OPC 10030 section
  8.3.2.2 requires. The previous binder wrote a scalar, which did not match the
  declared OneOrMoreDimensions ValueRank.
- A provider that cannot push is polled at the Variable's MinimumSamplingInterval
  rather than being installed once, so a non-pushing provider no longer serves
  its start-up sample with Good status forever.
- The three ISA-95 specific geolocation provider files are removed; their
  behaviour now comes from the shared seam and its in-memory implementation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8cbb8cd0-f0cb-4ab0-bea2-6202fbf69485
Review feedback on #4123 objected to ThrowIfNull and IsFinite being public
extension methods declared in the System namespace, where they are offered to
every consumer of the stack for every expression and compete with the
platform's own helpers.

They are removed from Polyfills in #4123 and reappear here, in Opc.Ua, next to
the coordinate transforms that are their only callers. Pre-existing code in the
stack uses the BCL's ArgumentNullException.ThrowIfNull, which is unrelated and
untouched.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8cbb8cd0-f0cb-4ab0-bea2-6202fbf69485
…thing

Review feedback on #4125. ArrayOf<T> implements INullable, so `default` is
the null array, which is a different thing on the wire from an empty one.
Browsing for children that do not exist means ''no children'', not ''value not
present'', so BrowseChildrenAsync now returns ArrayOf<ReferenceDescription>.Empty.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8cbb8cd0-f0cb-4ab0-bea2-6202fbf69485
@marcschier
marcschier force-pushed the marcschier/3827-3-positioning branch from 48423ea to 43a1d7c Compare July 31, 2026 12:01
@marcschier
marcschier merged commit c48c8b9 into master Aug 1, 2026
102 of 176 checks passed
marcschier added a commit that referenced this pull request Aug 1, 2026
…nector (#4126)

**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.

**Client** — `Opc.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.

**Connector** — `tools/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`.

**Sample** — `PumpDeviceIntegrationServer` 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 |

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8cbb8cd0-f0cb-4ab0-bea2-6202fbf69485
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-3-positioning 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