psmoveapi icon indicating copy to clipboard operation
psmoveapi copied to clipboard

Trigger and Move Button have a lot of dropouts

Open Jaywalker64 opened this issue 6 years ago • 14 comments

All Buttons except Trigger and Move have a high fidelity. Pressing them gives the expected response of pressed and released. The Trigger and Move are less responsive. The faster you click one of those, the less click events are published. This behaviour is seen in the example and example_new_api, Windows 7 and 10 with inbuilt Bluetooth.

Jaywalker64 avatar Feb 12 '19 10:02 Jaywalker64

Which controller are you using? Is it a ZCM1 or ZCM2 (see the label on the back)?

nitsch avatar Feb 12 '19 15:02 nitsch

ZCM2

Jaywalker64 avatar Feb 12 '19 16:02 Jaywalker64

How are you determining the rate of generated "click events"? Just from watching the console output in the example applications? Or by triggering actions with these buttons (e.g. lighting the bulb)? Or by actually measuring time offsets?

nitsch avatar Feb 12 '19 23:02 nitsch

I had different tests: 1.Console Output 2. Lighting the bulb 2.a with limiter 2.b w/o limiter 3. psmove.exe responsiveness : move button should switch light to white, this did not happen on every button click 4. Switched to desktop with external bluetooth adapter, problem still there.

What helped was re-pairing the psmove. After that the buttons did response correctly, but after some time the error reappears and Move/Trigger Button are coming through approximately 3 out of 10 times. Re-pairing every time this happens is unfortunately not an option and it is not fully tested, whether this workaround helps 100%.

Jaywalker64 avatar Feb 13 '19 14:02 Jaywalker64

Does the behaviour change if, prior to calling psmove_poll() in your update loop, you consume input reports that might have stacked up? Like so:

while (keep_running) {
    // consume old input reports
    while (psmove_poll(move)) {
        ;
    }

    // get latest input report
    if (psmove_poll(move)) {
        unsigned int buttons = psmove_get_buttons(move);

        // handle button presses etc.
    }
}

nitsch avatar Feb 13 '19 23:02 nitsch

When i do it like your example i only get infrequent updates from the move controller for all buttons.
For a simple test of the move button i did it like that:

 
           while (psmove_poll(it->second)) {
                ;
            }

            // get latest input report
            if (!psmove_poll(it->second)) {
                unsigned int buttons = psmove_get_buttons(it->second); 
           
                if (buttons & Btn_MOVE) 
                {
                    if (lastbuttons[Btn_MOVE] != ((buttons & Btn_MOVE) == 524288))
                    {                       
                        mStopWatch->stop();
                        int64_t elapsedTime = mStopWatch->elapsedMicroseconds();
                        printf("Move is pressed: %d\n", elapsedTime);
                        mStopWatch->start();
                    }                    
                }
                else
                {
                    if (lastbuttons[Btn_MOVE] != ((buttons & Btn_MOVE) == 524288))
                    {                    
                        mStopWatch->stop();
                        int64_t elapsedTime = mStopWatch->elapsedMicroseconds();
                        printf("Move is released: %d\n", elapsedTime);
                        mStopWatch->start();
                    }
                }
             }

My current implementation has this form:

int delay = psmove_poll(it->second);
while (delay != 0)
{
    delay = psmove_poll(it->second);
}
unsigned int pressed, released;
psmove_get_button_events(it->second, &pressed, &released);
for (unsigned int j = 0; j < mButtonMaskVector.size(); ++j)
{
    //handle buttons
}

Results for the time it took to get the release event after having the button pressed and releasing it(in microseconds): Move: 648426 Triangle: 63100

Pressed and released the Buttons as fast as i could(not highly sophisticated, but gives a overview). Move Button takes 10 times longer.

Jaywalker64 avatar Feb 14 '19 14:02 Jaywalker64

            // get latest input report
            if (!psmove_poll(it->second)) {
                unsigned int buttons = psmove_get_buttons(it->second); 

You got this check backwards. psmove_poll returns 0 on error or if no new data is available.

nitsch avatar Feb 14 '19 16:02 nitsch

I had the issue of infrequent updates using

  if (psmove_poll(it->second))    

as you wrote it. With

  if (!psmove_poll(it->second))    

i get updates. I know this is contra to the return value. That's why my second code does not have this. For clarification the first code is a different implementation than the second. Another question on top of that. The return of psmove_poll with no new data isn't that the status we want? We are up to date with the polling. Problematic is of course that it has the same value as error, whatever an error could occur.

Coming back to my original problem. In the device property all buttons are coming through perfectly. psmovecontroller The different ways of using psmove_poll did not improve my situation.

Does it make a difference that the move controller is a ZCM2E? Is there a possibility to check or get more information out of the HIDAPI about the psmove controller? Lost Data or something like that, to better test or get a more profound unterstanding?

Jaywalker64 avatar Feb 18 '19 14:02 Jaywalker64

The return of psmove_poll with no new data isn't that the status we want? We are up to date with the polling.

Yes, I realized that my suggestion was a bit broken. We would rather remove the additional check if (psmove_poll(move)) and just keep the initial while (psmove_poll(move)) {}.

Does it make a difference that the move controller is a ZCM2E?

I don't know. I could not yet test your problem on Windows.

Is there a possibility to check or get more information out of the HIDAPI about the psmove controller? Lost Data or something like that, to better test or get a more profound unterstanding?

You could just have a look at the implementation. On Windows, hidapi is using the HidD API for setup and feature reports, and regular file I/O for input and output reports (button data is in the input report). If you spot something that might help tracking down and fixing your problem, any feedback would be appreciated.

nitsch avatar Feb 19 '19 00:02 nitsch

Please also check out the docs in the header file: https://github.com/thp/psmoveapi/blob/master/include/psmove.h#L635

Here's the lowdown: If you want to process all events, you MUST use:

     while (psmove_poll(move)) {
         // process events here
     }

Note that ideally the event processing is "cheap" in the sense that it doesn't take forever (e.g. don't draw the UI or something, just update the internal state). If processing is "expensive" and takes a while, the system might start dropping input events if they are not consumed. This behavior is probably different in Windows, Linux and macOS.

If you do a while (psmove_pool(move)) {} (i.e. not actually process events when they arrive), you will read events and not handle them, so it's expected to not see all events. Same goes for checking if the result is zero -- when it is, it just means that since the last read there were no new updates.

The docs say:

 * \return a positive sequence number (1..16) if new data is
 *         available
 * \return \c 0 if no (new) data is available or an error occurred

I am not sure if this is the case for ZCM2E too (don't have one here for testing), but assuming it still is, you can also use the return value to see if there were any dropped frames.

Currently we take the sequence that is returned from this:

move->input.common.buttons4 & 0x0F

It might very well be that ZCM2E does not write this field (or writes it in a different spot). But anyway, psmove_poll() should still return a non-zero value in this case.

Can you for comparison try with the ZCM1 controller?

thp avatar Feb 20 '19 16:02 thp

Also, this part of the documentation:

 * How to detect dropped frames:
 *
 * \code
 *     int seq_old = 0;
 *     while (1) {
 *         int seq = psmove_poll(move);
 *         if ((seq_old > 0) && ((seq_old % 16) != (seq - 1))) {
 *             // dropped frames
 *         }
 *         seq_old = seq;
 *     }
 * \endcode

thp avatar Feb 20 '19 16:02 thp

After testing with a ZCM2 on Windows 10, I can confirm that the T button and the Move button are rather unresponsive while the other buttons seem to work just fine. I also tested a ZCM1 on the same system and it does not show this behaviour.

I will look into this more closely when I have a little more time.

nitsch avatar Feb 21 '19 01:02 nitsch

Can you for comparison try with the ZCM1 controller?

I only have ZCM2E Controllers.

I can confirm that the T button and the Move button are rather unresponsive while the other buttons seem to work just fine.

That are good news for me, that you could reproduce my issue. I had no time for further tests. But if you have a clue or could use some support, i gladly help out. Do you have an idea when you can look into the issue? I would very much appreciate fixing this.

Jaywalker64 avatar Mar 01 '19 13:03 Jaywalker64

Do you have an idea when you can look into the issue? I would very much appreciate fixing this. I am currently swamped with work. So it is probably not going to happen soon, I am afraid.

nitsch avatar Mar 05 '19 22:03 nitsch