Jumpy readings from Space Navigator using DI8 (Direct Input)

Post questions, comments and feedback to our 3Dconnexion Windows Development Team.

Moderator: Moderators

timcoolman
Posts: 7
Joined: Mon Apr 11, 2011 10:04 am

Jumpy readings from Space Navigator using DI8 (Direct Input)

Post by timcoolman »

I am using Direct Input to poll my Space Navigator at ~30 times per second. I use the values retrieved to move my virtual camera about a DirectX 10 scene. For the most part, this is working beautifully. However, I have recently noticed that as I move the camera, it doesn't seem to move as smoothly as it should.

I added some code to output to my console the values read each time it polls the device. What I found is that for a given axis, the value seems to jump up about 33% every several readings. For example, if I push the knob all the way down and hold it there, I will get 6-10 readings in a row at -700, then one at -1050, then 6-10 at -700, then one at -1050, and so on. This doesn't only happen when I max/min out an axis though, it will also, for example, read at -55 several times in a row, then jump to -73.

This jump appears to occur consistently on any axis, but independent from each other.

What is even more strange, is that when I run the example DI8 application provided by 3DConnexion, the same thing happens, but in reverse... If I push the knob all the way down (just as I described in the example above), most readings will be at -1050, with a -700 thrown in every 6-10 readings.

I'm wondering if anyone else has had this problem. Am I doing something wrong? Is it a hardware problem? Or is it just an expected side-effect of using Direct Input that I'll have to live with?

Otherwise I'm very pleased and impressed with this device. Any tips anyone can give me will be greatly appreciated.

-Tim
transcendent
Posts: 2
Joined: Wed Aug 10, 2011 6:31 am

Post by transcendent »

I'm having the same problem with Space Navigator and DirectInput, but only if I increase the polling frequency higher than 30 Hz. If I set the frequency to 100 Hz, the values will sometimes be zero, which seems to indicate that perhaps the device can't keep up with the polling.

The weird thing is that if I decrease the frequency, the limits then go beyond +/- 1050 (e.g. they become +/- 1750 at 15Hz). It almost feels as if there's some accumulator that gets "drained" every time the device get polled, so if you poll more frequently, it gets filled to a lower value, and if you poll less frequently, it gets filled to a higher value.

Does anyone have an insight as too why this is happening, and how to fix it? My application depends on the min/max range being fixed, and this behaviour is obviously undesirable.

(The results are the same in both my code and with the sample provided by 3DConnexion.)
ngomes
Moderator
Moderator
Posts: 3321
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Post by ngomes »

Hi transcendent,

I think that is the normal way that DirectInput works (sort of like with the normal mouse): it accumulates the device "counts" and then empties whenever the application polls the data.

Try setting the dwData member of the DIPROPDWORD structure to DIPROPAXISMODE_ABS (should be set to _REL) and see if it changes the behaviour to what you'd expect.
Nuno Gomes
transcendent
Posts: 2
Joined: Wed Aug 10, 2011 6:31 am

Post by transcendent »

Ah, thanks for that bit of info. I tried using DIPROPAXISMODE_ABS, but this creates the problem that the axes' values don't return to zero I let go (so it ends up integrating them over time). DIPROPAXISMODE_ABS works perfectly on the SpacePilot Pro, so we're going to support only the latter for the time being.
timcoolman
Posts: 7
Joined: Mon Apr 11, 2011 10:04 am

Re: Jumpy readings from Space Navigator using DI8 (Direct In

Post by timcoolman »

I realize it has been quite a long time since I originally posted this topic. This issue fell in priority to the overall development progress of our application. Now we are at a point where I can take a look at this again, which we have just been dealing with in the meantime.

Using DirectInput8 to capture the state of a Space Navigator device, I still can not seem to get consistent readings. I have tried using different polling frequencies as well as changing the axis mode to DIPROPAXISMODE_ABS (it may be worth noting that the axis mode actually seems to have the reverse behavior of what I would expect in axis coordinates). And since it had been some time since I've worked on this problem, I did download the latest device drivers from the website, but the issue continued.

As for the way DirectInput normally works, I am not sure about whether or not other devices accumulate counts over time in between each call to poll the device state. I considered that as a possibility of what was happening here, but after some investigation and debugging, I feel confident in my conclusion that it isn't the case - at least not in a predictable way that one can code around. While it does seem that the time from one poll to the next has an effect on the values returned, the relationship between time and return values isn't directly linear or in a high enough resolution to effectively compensate with code.

In my testing, when I poll at ~30 Hz and max out any given axis, the output for that axis will be MOSTLY 700 - except for maybe 2-3 polls each a second, which will jump up 50% to 1050. If I decrease the frequency, the output from a maxed axis maybe be MOSTLY 1050 or 1400, but still have those very specific interval jumps a few times per second. This is with very little variation in my polling frequency (which I have logged to ensure my polling wasn't experience lag spikes; also, the same behavior can be seen in 3Dconnexion's DirectInput sample). And as I mentioned in my original post, these jumps don't only occur when the axis is at it's max level. At the ~30 Hz frequency, as I gradually move an axis from center to positive, I will see it climb from 0 to 700, apparently with a granularity of 1, with those jumps occurring along the way (the jumps do seem to be relative to the current value; it won't jump from 50 to 1050, but maybe 50 to 75).

Besides just causing non-fluid movement about our 3d scenes, this also produces unpredictable behavior when our application happens to experience a framerate drop. Because I don't feel like I can count on the DI8 readings to be an accurate representation of movement over time, I use my own timer and polling frequency values as a multiplier on the readings to get fluid movement over time. Under normal frame rate, this issue just results in small, consistent, choppy jumps in movement. But in the event of a slow frame, the value of my timer is compounded on top of the higher value returned by the device to result in an exaggerated jump in the 3d scene.

Any support I can get on this issue would be much appreciated.
ngomes
Moderator
Moderator
Posts: 3321
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Re: Jumpy readings from Space Navigator using DI8 (Direct In

Post by ngomes »

Hi timcoolman,

From what you described, it would appear that you need to move away from using DI accumulation of event "counts". In other words, it may work better for you to use DIPROPAXISMODE_ABSDIPROPAXISMODE_REL.

You also mention that you tried DIPROPAXISMODE_ABSDIPROPAXISMODE_REL. What was the issue with it? It should set DI to report the device "state" rather than trying to integrate the count over time.

If you use "_ABS""_REL" then you should be able to control your scene change (camera movement) proportionally to the device cap displacement: the further the user pushes on the cap, then faster will your camera move and/or rotate around.

You should able to poll using a timer and detect when the count level comes down to zero, at which point to stop changing the camera. Keep in the mind that, when using a 3D mouse, users expect to have a minimum frame rate. Anything below 10 fps is a poor experience and best is achieved going above 30fps. One the tactics we use is to degrade visual quality on complex scenes to maintain the fps above 20 fps or so.
Last edited by ngomes on Thu Jan 24, 2013 7:07 am, edited 1 time in total.
Reason: Correct confused flag reference.
timcoolman
Posts: 7
Joined: Mon Apr 11, 2011 10:04 am

Re: Jumpy readings from Space Navigator using DI8 (Direct In

Post by timcoolman »

Well, I also mentioned that _ABS doesn't seem to work the way that would expect, which is to act like a joystick, and return the absolute position of the knob on each axis, since, unlike a mouse, the device has a physically limited range of motion. So on a given axis, I would expect _ABS to return zero when the knob is at its starting position, and some maximum level when you push all the way to one side, and an inversely negative value when you push all the way in the opposite direction, then back to zero when at rest. Like you said, the time between polling would have no effect on the values.

However, like transcendent mentioned in his post, the value doesn't return to zero when the knob returns to center. Instead, it is like the device is storing a counter for each axis. This counter doesn't appear to be affected by polling. But let's take movement on the X-axis for example. If I lightly push the knob to the right and hold it, the X value will continuously increment gradually. The further I push it to the right, the faster the value increments. If I release the knob so it returns to center the value remains where it was at the time of the release. To get it back to zero, I have to push the knob the other direction do make the value decrement. So if I were to simply "bump" the knob to the right over and over for a period of time, the value would continue to increase up into the the tens of thousands.

So what I tried to do with that is code in my own "relative" behavior in hopes that it would eliminate the spikes I've been getting. So in my code I would store the last polled JoyState, acquire a new one, then use the delta of the two to control my virtual camera. This worked, but the spikes still existed, giving me choppy movement (although this would probably eliminate the framerate drop behavior I mentioned).

I understand that for fluid animation and user input response the frame rate should be above 30 fps, and for the most part our software runs at 60 fps or better. I was simply pointing out the compounded effect that would occur in the event of an unexpected frame lag spike.

I really believe that the axis-value spikes that I'm talking about must be a device bug, probably limited to the DirectInput implementation. Without these spikes I could probably use either the _REL or _ABS modes just fine (based on what I've learned from you about _REL, I think I could use it by removing my own polling timer as a multiple on the axis value). I don't believe these spikes are related to the _REL behavior of accumulated counts.
ngomes
Moderator
Moderator
Posts: 3321
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Re: Jumpy readings from Space Navigator using DI8 (Direct In

Post by ngomes »

You shouldn't see any data spikes on the raw device data. If there are some, then the device is (somehow) malfunctioning. Do you have a second 3D mouse to compare?

Do you have a requirement to use DirectInput? If not, what are your requirements for 3D mice?
timcoolman
Posts: 7
Joined: Mon Apr 11, 2011 10:04 am

Re: Jumpy readings from Space Navigator using DI8 (Direct In

Post by timcoolman »

This problem occurs when using multiple Space Navigator devices. Not to mention transcendent reported having the same issue earlier in this thread. As I mentioned, the DirectInput sample provided on your FTP site does the same thing. You could probably quickly determine whether or not it is a broad device issue by running that sample.

I am not required to use DirectInput, it just seemed like the quickest way to implement in my application because I'm already using DirectInput for keyboard input. If this probably cannot be solved, I could try out your regular SDK. I just hope it is quick and painless to implement.
jwick
Moderator
Moderator
Posts: 3331
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Re: Jumpy readings from Space Navigator using DI8 (Direct In

Post by jwick »

This problem only occurs when using multiple devices at the same time? Input from both at the same time, or one, then the other?
ngomes
Moderator
Moderator
Posts: 3321
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Re: Jumpy readings from Space Navigator using DI8 (Direct In

Post by ngomes »

Hi timcoolman,
I am not required to use DirectInput, it just seemed like the quickest way to implement in my application because I'm already using DirectInput for keyboard input.
I agree. If you're already have a dependency on DirectInput (DI), it makes sense to use it to add 3D mouse support. If you were using DI just for the 3D mouse, we could consider an alternative.

Regarding the problem at hand, the "spikes" that you are seeing (I confirmed the behaviour using the DI8ExamplePoll sample) are caused by a sampling issue: DI collects the "count" value per axis between each poll and, as your program polls at a different rate from the device's, you will see the accumulated values for one more (or less) data packet.

Take the example where the device is sending the value "100" on a single axis. If your program lets DI collect three packets, you will see it retrieving a value of "300" and, occasionally the value of "200" when it misses one the packets. Depending on the exact rate at which the program polls, you may see it missing or gaining the count of one packet.

As far as we know, this is how DI works. It will always collect "count" data in one form or the other (depending on _REL, or _ABS flags).

The question is how you go about smoothing the data.

You can poll at more than 60 Hz. Since devices send data at 60 Hz, if you poll faster you will get either zero or a single packet count value (non-accumulated). If you poll twice between before a packet is received, you will get all axes set to zero so your program will need to detect a cap release by waiting enough time (say 200 ms) of zero values before considering the cap to have been released.

If polling at that rate is an issue, you can try polling at slower rate and use a running average (say the last three polled packets). You'll decrease the responsiveness of the device but, if polled sufficiently fast, users will not perceive it.

Another tactic (which you could combine with the previous) is to use a high resolution counter to measure the time between polls (the accumulation time) and scale the return value accordingly.
jwick
Moderator
Moderator
Posts: 3331
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Re: Jumpy readings from Space Navigator using DI8 (Direct In

Post by jwick »

Or a better alternative may be to use the interrupt to signal you that some new data has arrived, then poll to get that value and use that value repeatedly until the interrupt tells you another value arrives.

IOW, draw at your regular rate using the most up-to-date information available (as provided by the interrupt). If you draw faster than the device and DI provide data, you will reuse the last data. As far as you know the user is still applying the same force.

When the interrupt says the device went to zero (the user let go), the interrupt will tell you this.
timcoolman
Posts: 7
Joined: Mon Apr 11, 2011 10:04 am

Re: Jumpy readings from Space Navigator using DI8 (Direct In

Post by timcoolman »

jwick wrote:Or a better alternative may be to use the interrupt to signal you that some new data has arrived, then poll to get that value and use that value repeatedly until the interrupt tells you another value arrives.
Do any of your samples demonstrate how to detect the device interrupts? This would be the first time I've used interrupts as signals.

Thank you both for all this information. It is really helping me out.
jwick
Moderator
Moderator
Posts: 3331
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Re: Jumpy readings from Space Navigator using DI8 (Direct In

Post by jwick »

The other example on the ftp site (DI8Example) is an event driven (interrupt driven) example.
ngomes
Moderator
Moderator
Posts: 3321
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Re: Jumpy readings from Space Navigator using DI8 (Direct In

Post by ngomes »

timcoolman wrote:Thank you both for all this information.
Thanks for supporting our devices in your application.

I think you still see the accumulation of data even with the event approach. Also note that there's something odd with the DI8Example demo: on my test system, I need to put the window on the background and back to foreground before it begins to receive events.
Post Reply