Skip to content

Vhi.LSLCommunicationController

VHI_godot

Vhi

LSLCommunicationController Class

All Lab Streaming Layer I/O for VHI - the only node that touches LSL directly (and even then only through LSLWrapper, never SharpLSL).

One stream per DOF, in. Every control VHI exports is its own LSL stream, named by its own address and one channel wide: vhi.prediction.index, vhi.control.pose.thumb.flexion, and their siblings — the same names GetControlManifest publishes. A sample is applied to the hand the moment it arrives, and the DOFs that did not deliver hold what they were last commanded to. There is no whole-pose frame and nothing waits for one: the DOFs are independently actuated, may come from different producers and may update at different rates, so a hand whose index has moved and whose thumb has not is a real pose.

Two nine-channel outlets, out, unchanged: VHI_Control and VHI_Predict publish each hand's whole pose at 60 Hz. A read-back is a recording, and a recording wants one row per instant.

Stream resolution blocks ~1 s so it runs on a background Task.Run thread; results and log lines are marshalled back to Godot's main thread via CallDeferred. Sample pulls themselves are non-blocking and happen in _Process. Streams are \<i>found\</i> by name, but a found stream is only opened when it is \<b>exactly one channel wide\</b> — see Vhi.LSLCommunicationController.ResolveMissingInletsAsync.

public class LSLCommunicationController : Godot.Node

Inheritance System.Object → Godot.GodotObject → Godot.Node → LSLCommunicationController

Fields

LSLCommunicationController.ControlOutletName Field

Name of the LSL outlet that publishes the control hand's pose at 60 Hz. Consumed by MyoGestic as a regression-target source.

public string ControlOutletName;

Field Value

System.String

LSLCommunicationController.ControlPoseStaleAfterSeconds Field

Silence after which a control-pose DOF's inlet is assumed gone.

public float ControlPoseStaleAfterSeconds;

Field Value

System.Single

Remarks

Presence is the only thing that hands the control hand to these streams, so "the producer stopped" has to be observable here rather than inferred from an error — PullSample(object, float[], double) catches every exception and returns 0.0, so no error ever reaches this file and a lost producer is indistinguishable from an idle one. The clock is the whole signal.

It settles two things, not one: the DOF stops counting toward ControlPoseLive, and its inlet is dropped so the by-name resolve can find whoever publishes that name next. Without the second, the first producer to exit cleanly pinned that inlet to a corpse for the life of the process.

LSLCommunicationController.ExpectedChannels Field

Channel count of the 9-DOF hand pose the two outlets publish.

public int ExpectedChannels;

Field Value

System.Int32

LSLCommunicationController.PoseConvention Field

What +1 means on both pose outlets, published in their metadata.

public const string PoseConvention = "standard";

Field Value

System.String

Remarks

standard: +1 is the direction the channel's name denotes, 0 is rest, the domain is [-1, 1]. Recordings made before this existed are in legacy — the rig's own units, where the five flexion channels ran the other way — and a reader that finds no pose_convention must assume that, not this.

LSLCommunicationController.PredictedOutletName Field

Name of the LSL outlet that publishes the predicted hand's pose at 60 Hz. For monitoring / recording alongside the EMG.

public string PredictedOutletName;

Field Value

System.String

LSLCommunicationController.PredictionStaleAfterSeconds Field

Silence after which a prediction DOF's inlet is assumed dead and dropped.

public float PredictionStaleAfterSeconds;

Field Value

System.Single

Remarks

Generous on purpose. A `ControlBus` outlet sends at its own rate whether or not the values changed, so real silence means the producer went away — but a script that pushes a frame and then sleeps is also legitimate, and dropping its inlet only costs a re-resolve. Long enough not to punish that; short enough that replacing an outlet (which the control-map editor does on every save) reconnects while you are still looking at the hand.

Properties

LSLCommunicationController.ControlPoseLive Property

Whether \<i>any\</i> control-pose stream is delivering right now.

public bool ControlPoseLive { get; }

Property Value

System.Boolean

Remarks

`ControlHandSkeleton` reads this to decide whether to render what it was commanded or run its movement state machine. It is the whole of the old `Declare(control_pose=true)` handshake: publish a stream and the hand follows it.

Any, not all. There are nine control-pose streams now and a producer is under no obligation to publish more than one — driving a single DOF from a single producer is the capability this shape exists for, so requiring all nine would mean such a producer never took the hand at all. One live DOF is a client driving this hand, and the eight that are silent are DOFs nobody is driving, which is not the same as nobody driving the hand. The falling edge is therefore the last stream going quiet, which is when the hand is genuinely unclaimed and StopToRest is right.

Methods

LSLCommunicationController.SendControlData(List\<float>) Method

Push a 9-DOF pose sample to the VHI_Control outlet. The sample is silently dropped if the outlet has not been created or if its length does not match ExpectedChannels. Called by ControlHandSkeleton every _PhysicsProcess tick.

public void SendControlData(System.Collections.Generic.List<float> data);

Parameters

data System.Collections.Generic.List<System.Single>

9 float channels - see the LSL stream reference for the channel layout.

LSLCommunicationController.SendPredictedData(List\<float>) Method

Push a 9-DOF pose sample to the VHI_Predict outlet. Same shape and contract as SendControlData(List<float>). Called by PredictedHandSkeleton every _PhysicsProcess tick.

public void SendPredictedData(System.Collections.Generic.List<float> data);

Parameters

data System.Collections.Generic.List<System.Single>

9 float channels - see the LSL stream reference for the channel layout.

what System.Int32

delta System.Double