OSVR / OSVR-Leap-Motion

OSVR Leap Motion plugin
Apache License 2.0
18 stars 14 forks source link

Using and testing the analog interface #7

Closed zachkinstner closed 9 years ago

zachkinstner commented 9 years ago

I'm not sure whether the plugin is sending the analog data incorrectly, or perhaps something strange is happening with the AnalogCallback_cpp.exe testing app and Unity client.

The plugin uses osvrDeviceAnalogSetValues in Analog.cpp to send an array of three numeric values. Using console output, I can confirm that the update() function is executing, and that the array contains the expected values. I initially started using the osvrDeviceAnalogSetValue (singular value) function, but the docs suggested sending the array of values all at once. In both cases, I was unable to receive these analog values in the Unity client.

The plugin sends a size of 3 to the osvrDeviceAnalogConfigure function, and also provides a count of 3 in the device descriptor JSON.

zachkinstner commented 9 years ago

Here's the output from the testing app. Note that the plugin currently routes the "hand count" analog semantic path to the /controller/left/trigger alias path.

[OSVR] Connecting to default (local) host
[OSVR] Client context initialized for com.osvr.exampleclients.AnalogCallback
[OSVR] Got connection to main OSVR server
[OSVR] Got updated path tree, processing
[OSVR] Connected 0 of 0 unconnected paths successfully
[OSVR] Connection process took 19ms: have connection to server, have path tree
[OSVR] Interface initialized for /controller/left/trigger
[OSVR] Constructed an AnalogHandler for com_osvr_LeapMotion/Controller@localhost
[OSVR] Successfully produced handler for /controller/left/trigger
Library shut down, exiting.
[OSVR] Client context shut down for com.osvr.exampleclients.AnalogCallback
zachkinstner commented 9 years ago

Here's the code I'm using to test with the Unity client. The HandleAnalogUpdate callback method is never called. I've tried connecting to various paths (raw analog, semantic, alias) without any luck.

private Interface vHands;
private AnalogCallback vHandsCallback;

public void Awake() {
    DLLSearchPathFixer.fix();
    vContext = new ClientContext("com.osvr.LeapMotion.Test");
}

public void Start() {
    vHands = vContext.getInterface("/controller/left/trigger");
    vHandsCallback = HandleAnalogUpdate;
    vHands.registerCallback(vHandsCallback, IntPtr.Zero);
}

public void Update() {
    vContext.update();
}

private void HandleAnalogUpdate(IntPtr pUserdata, ref TimeValue pTimestamp, ref AnalogReport pReport) {
    Debug.Log(" * ANALOG "+pReport.sensor+" / "+pReport.state); //never gets called
}
zachkinstner commented 9 years ago

I'm currently using:

zachkinstner commented 9 years ago

@rpavlik noted in issue #6:

you're using a "raw" way of doing that - there is a better way of doing callbacks now using .NET events (example in managed-osvr)

Working from this AnalogCallback example from Managed-OSVR, I tried a new approach (code below). I thought it might resolve this issue, but it still doesn't receive any analog updates.

private AnalogInterface vHands2;

//same Awake() and Update() as the previous code example

public void Start() {
    vHands2 = AnalogInterface.GetInterface(vContext, "/controller/left/trigger");
    vHands2.StateChanged += HandleAnalogStateChanged;
}

private void HandleAnalogStateChanged(
            object pSender, TimeValue pTimestamp, Int32 pSensor, Double pReport) {
    Debug.Log(" * ANALOG2: "+pSensor+" / "+pReport); //never gets called
}

Note: I also tried it with the nested-using approach shown in the example -- the only output I get is "Library shut down; exiting." after the faux-update loop is complete.

rpavlik commented 9 years ago

Are you actually using the /controller/left/trigger path as you show here? That's unlikely to give you any data unless you have either set up an alias manually or you have a Razer Hydra plugged in. Though, I see you mention that you did set it up. The output of osvr_print_tree would be useful here.

zachkinstner commented 9 years ago

Here are the analog-related paths from osvr_print_tree:

[   DeviceElement] /com_osvr_LeapMotion/Controller
                     - corresponds to com_osvr_LeapMotion/Controller@localhost

[...]

[InterfaceElement] /com_osvr_LeapMotion/Controller/analog
[   SensorElement] /com_osvr_LeapMotion/Controller/analog/1
[   SensorElement] /com_osvr_LeapMotion/Controller/analog/0
[   SensorElement] /com_osvr_LeapMotion/Controller/analog/2

[...]

[    AliasElement] /com_osvr_LeapMotion/Controller/semantic/count/fingers
                     -> /com_osvr_LeapMotion/Controller/analog/1
[    AliasElement] /com_osvr_LeapMotion/Controller/semantic/count/hands
                     -> /com_osvr_LeapMotion/Controller/analog/0
[    AliasElement] /com_osvr_LeapMotion/Controller/semantic/count/tools
                     -> /com_osvr_LeapMotion/Controller/analog/2

[...]

[    AliasElement] /controller/left/trigger
                     -> /com_osvr_LeapMotion/Controller/semantic/count/hands
[    AliasElement] /countTest/fingers
                     -> /com_osvr_LeapMotion/Controller/semantic/count/fingers
[    AliasElement] /countTest/hands
                     -> /com_osvr_LeapMotion/Controller/semantic/count/hands
[    AliasElement] /countTest/tools
                     -> /com_osvr_LeapMotion/Controller/semantic/count/tools
zachkinstner commented 9 years ago

Via email:

[...] at the moment we believe that the analog interface and the test programs that demonstrate it work, so we believe this is likely a bug on Zach's side

After a couple "test" changes, I able to get analog values in Unity. Here's what I found:

zachkinstner commented 9 years ago

The analog interface spec (emphasis mine) says:

In the transport, the value of all channels/sensors is reported with each message. Thus, whether a device sends a single channel update or a full new set of channel values, the full data is sent in each message. Receipt of a callback on a specific channel does not necessarily mean that channel was modified (in fact, no filtering is done, so the same data could be sent repeatedly -- by design, since the measured data may not have changed), just that the device reported updated state.

This isn't what I'm experiencing -- the analog event occurs only when the value changes.

Since the Leap plugin uses the analog interface to also provide "config" and "status" values, it would need the interface to function as described in the spec. There may be status values that rarely change, for example, and apps may need to access this data on-demand (rather than waiting for a "value change" event).

zachkinstner commented 9 years ago

With the temporary changes in place (using osvrDeviceAnalogSetValue with an incrementing value), I am able to receive analog events in my Unity testing scene. Both the "raw" and "new" approaches (described in earlier comments) receive these events.

gfrolov commented 9 years ago

@zachkinstner , I reproduced the issue that you described, where Analog values weren't showing up in the AnalogCallback_cpp.exe. I setup the plugin and verified that device was indeed sending new values which still weren't showing in the client application. The problem was on the client side where the range that's used to iterate over sensors was not getting setup properly, so it was only reporting value of 1 sensor. I fixed the order and the values are now coming through. That should fix this issue. The latest OSVR binary should have this fix for that so you can give it a try.

zachkinstner commented 9 years ago

I can confirm -- I'm now able to access the analog values as expected. For the Leap Motion use case, I found it was easier to obtain the analog values on every Update() vs. handling the analog "change" events. See LeapAnalogs.cs in the commit referenced above.