Files
UA-.NETStandard/samples/Robotics/IntentEnabledRobot/README.md
6fe5399510 Add UaLens desktop engineering workspace (#4822)
# Description

Add **UaLens**, an Avalonia desktop engineering workspace for OPC UA
exploration, monitoring, typed editing, administration and guided
companion-specification tasks.

This is a **new draft PR for `pisrapp` against `master`**, replacing
closed, unmerged #4462 without reopening it. The shared prerequisites
(#4801, #4802, #4803, #4804 and #4806) have all merged; their
implementation is no longer part of this PR's delta.

### Scope

- Multi-document workspace with connection, security and identity
controls; browsing, subscriptions, events, alarms, history, writes and
method calls.
- Offline NodeSet2 exploration, typed scalar/array/matrix editing,
certificate/GDS and account/role tools.
- UaLens companion workflows, repository sample launching and the Aspire
AppHost.
- PubSub commissioning and capture/replay integration, plus the
UaLens-facing OpenUSD viewport and rendered Vision workflows.
- UaLens projects, test assemblies, UI assets, guides,
solution/dependency entries, desktop test wiring and delivery workflows.

Head **`6f46c51fcfef275059bbe77ef39c64c19ebc1053`** is one UaLens-only
commit directly above master
**`44a8cb277df450162c29313e2f4c862e7c683752`**. The rebase required no
conflicts. All **967 UaLens file blobs**, the full-index binary patch,
commit-message text and author/co-author attribution are unchanged from
the previously published layer. There is **no implementation delta under
`src/`**. The original history is retained in recovery refs, including
`refs/pr-stack/backups/master20261017/ualens`.

No feature was disabled, and no export/path safeguards, native
acceptance criteria, test assertions or CI gates were weakened. The four
previously recorded blank-line-at-EOF findings in the UaLens dialog
files remain unchanged; they are not reported as newly fixed.

### Validation

Fresh validation ran on the **exact PR head `6f46c51f`**, using the
existing pinned SDK **10.0.401**, normal repository analyzers and
physical/non-linked build outputs:

```powershell
$d = 'D:\git\UA-.NETStandard_master\TestResults\ualens-528-deep-repro\sdk\dotnet.exe'
$b = 'D:\git\UA-.NETStandard_master\TestResults\ua-stack-feedback20261016'
$r = 'C:\Users\mschier\.copilot\session-state\abd33a2e-7139-44e1-9912-6e4451102b4e\files\ualens-new-draft20261017-net10'
$env:DOTNET_ROOT = Split-Path -Parent $d
$env:DOTNET_ROOT_X64 = $env:DOTNET_ROOT
$env:DOTNET_CLI_TELEMETRY_OPTOUT = '1'
$env:PATH = $env:DOTNET_ROOT + [IO.Path]::PathSeparator + $env:PATH

& $d test 'tests\Opc.Ua.Lens.Tests\Opc.Ua.Lens.Tests.csproj' --no-restore --artifacts-path $b -c Release -f net10.0 -p:CustomTestTarget=net10.0 --filter 'TestCategory!=LongRunning&TestCategory!=Stress' --logger 'trx;LogFileName=ualens-new-draft.trx' --results-directory $r --blame-hang --blame-hang-timeout 3m --blame-hang-dump-type none --verbosity minimal
# PASS, exit0: Passed: 4524, Failed: 0, Skipped: 0.
```

The saved TRX contains **4524 Passed and 44 explicit/prerequisite
NotExecuted records** (4568 total). The repository verdict helper
confirms zero failed tests, fixture setup/teardown failures or run-level
errors, without toleration. No compiler/analyzer diagnostics were
emitted. Logs, TRX and `ualens-new-draft20261017-validation.json` retain
this exact-head evidence.

**Not run for this new draft:** the full `UA.slnx` net48/net10 matrix,
fresh coverage, other desktop TFMs, application-desktop/native workflow
suites, NativeAOT, GPU/per-RID/installed-runtime or package-release
qualification. UaLens targets .NET8+; no net48 UaLens execution is
claimed. Remote CI and CodeQL are not yet claimed green. Historical
native diagnostics and successful managed tests are not substitutes for
rendered-frame or release acceptance.

The previous PR and retained session artifacts preserve the full
extraction, review, failed-attempt and diagnostic history. Historical
intermittent CI failures were not silently reclassified as root-cause
fixes; no old diagnostic grants or producer/release operations were
reused for this PR.

## Related Issues

_Reference all GitHub issues this PR addresses. If there is no issue
yet, open one and link it here._

_If this is a relatively large or complex change, a design must have
been discussed in the related tracking issue and signed off (which
becomes the Architectural Decision Record (ADR))._

- References #4461, the existing closed UaLens design/qualification
tracking issue; no new design approval is implied.
- Replaces closed, unmerged #4462 for the remaining UaLens work.
- Builds on merged prerequisites #4801, #4802, #4803, #4804 and #4806;
this PR does not close them.

## Checklist

_Put an `x` in the boxes that apply. You can complete these step by step
after opening the PR._

- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [ ] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.

The test/coverage item remains unchecked because fresh coverage was not
collected. This draft does not claim CLA confirmation, full-matrix
clearance, native qualification or completed review.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Alexander Köpke <alexander.koepke@microsoft.com>
Co-authored-by: Copilot <Copilot@users.noreply.github.com>
2026-10-21 17:18:19 +02:00

6.5 KiB

IntentEnabledRobot

This sample is a small OPC UA Robot Intent server for one stationary UR5e-style arm. It publishes Server/RobotIntent/Controllers/UR5eIntentController, the controller's frames, tools, locations, axes, outputs, programs, description, safety state and OpenUSD representation.

This sample uses a UR-style six-axis arm and numerical IK. The BinPickingCell sample injects a separate analytic four-axis palletizer through the shared ISimulatedArmKinematics executor seam; changing the bin-picking robot does not change this standalone sample's model or behavior.

Run

dotnet run --project samples\Robotics\IntentEnabledRobot\IntentEnabledRobot.csproj -- --host localhost --port 62840

Default endpoint: opc.tcp://{host}:{port}/IntentEnabledRobot with port 62840. The default host is localhost so the generated server certificate matches local clients. Stop the server before rebuilding the sample; the running process holds its assemblies open.

For demonstration only, the sample maps anonymous users to the well-known Operator role so the command methods can be exercised without user-management setup. A production server should keep the Robot Intent command methods role-restricted and grant Operator only to authenticated operator identities.

For a finite, noninteractive run, supply --run-seconds (1 through 3600). --pki-root selects an absolute private certificate-store directory and --autoaccept false rejects untrusted certificates. These options are used by UaLens's explicitly selected, managed .NET 10 sample launcher, which applies its own shorter lifetime bound. For example:

dotnet run --project samples\Robotics\IntentEnabledRobot\IntentEnabledRobot.csproj -- `
    --host 127.0.0.1 --port 62840 --pki-root C:\Temp\IntentRobotPki `
    --autoaccept false --run-seconds 60

Finite runs do not start the interactive safety-console reader, so blocked console input cannot hold shutdown open. The simulated safety source and method authorization remain active. Without --run-seconds, the console is interactive. Robot Intent is a draft model, separate from the published OPC 40010 Robotics model.

Address space

The standalone Robot Intent node manager creates Server/RobotIntent/Controllers. The sample adds one IntentControllerType named UR5eIntentController with:

  • frames World, Base, MechanicalInterface and GripperTcp linked by HasFrameParent;
  • six revolute axes J1..J6, indices 0..5, with limits of +/-360 degrees except J3 at +/-180 degrees to match the simulated kinematics file;
  • one fitted tool ParallelGripper whose TCP frame is the Tool role frame;
  • locations Bin, Fixture, Inspect and Handoff;
  • outputs GripperOpen and BenchLight;
  • programs Home and PickAndPlace;
  • a robot description with a six-joint kinematic chain, reach radius 0.85 m and payload limit 5 kg.

Capabilities

The server truthfully separates host capabilities from executor capabilities. MissionsSupported, MissionHorizonSupported and MissionBranchingSupported are true because IntentControllerHost implements mission submission, updates, cancellation, horizon release and branching step graphs; the executor receives only the individual released intent steps. TrajectorySupported is true because the simulated executor accepts a complete TrajectoryIntentDataType, follows its timed points and reports trajectory deviation. BlendingSupported and ForceControlSupported are false because the simulation neither blends motions nor regulates contact force.

The generated Robot Intent methods pass the StopMode argument to the executor. The simulation differentiates it as application stop urgency only: QuickStop decelerates with the configured acceleration bound, ProcessStop uses a moderate deceleration, OnPath uses a gentler deceleration along the path, and EndOfCycle / EndOfInstruction finish the current simulated motion segment. These modes do not select or imply IEC 60204-1 stop categories.

OpenUSD mapping

The stage serves Bench.usda as the root layer and arm.usda / gripper.usda as referenced assets. Viewer clients discover picked target prims through OpenUSD live bindings, not a hardcoded table. Each OpenUsdRepresentation is mounted on its represented Object with HasAddIn through the shared CreateRepresentation authoring helper. Browse Server/OpenUSD/Representations; for each representation, browse its live bindings and read the binding with SourceSemanticId = "RobotIntent.Location". Its TargetPrimPath is the USD prim and its SourceNodeId is the corresponding LocationType NodeId.

USD prim (TargetPrimPath) SourceNodeId points to Pose in frame world Quaternion (x, y, z, w)
/World/Targets/Bin Bin (0.41, -0.28, 0.829) (0, 0, 0, 1)
/World/Targets/Fixture Fixture (0.48, 0.26, 0.829), rz 25� (0, 0, 0.2164396, 0.9762960)
/World/Targets/Inspect Inspect (-0.25, 0.30, 0.829), rz -20� (0, 0, -0.1736482, 0.9848078)
/World/Targets/Handoff Handoff (-0.46, -0.26, 0.829), rz 40� (0, 0, 0.3420201, 0.9396926)

The location poses are authored in the World Robot Intent frame and numerically match the USD target coordinates; the arm Base frame is also a child of World, so clients can transform consistently.

Target moves

The four published puck poses are reachable, but a straight Cartesian line between arbitrary pucks can cross a joint-limit boundary in this compact UR5e-style simulation. To make the click-to-target sample deterministic, the safety-aware sample executor handles a submitted LinearMoveIntentDataType as a cell-level target move: it first performs an internal joint move to a short pre-target approach pose, then executes the requested linear move into the published target pose. The externally visible command is still the client's linear intent and the final Result reports the published target pose; the internal joint segment demonstrates why Robot Intent exposes both joint and linear motion semantics.

Safety demonstration

Type commands into the server console:

  • stop trips a simulated protective stop; submitted intents fail with NotPermittedInMode.
  • limit 0.05 enables a safe speed limit; faster Cartesian motions fail with SafetyLimitExceeded.
  • reset returns the simulated safety source to nominal.

The safety variables are read-only reports and there is no command method that clears a stop or changes a safe-motion function.