Joystick Axis inputs not working correctly

I’m using a Xbox 360 controller with the wireless receiver. The inputs are not working correctly in a number of ways so I think I should start troubleshooting with the most glaring issue: The input values jump all over the place while holding the specified axis in a “full on” position (although the values jump no matter what position you hold the axis at).

This output is from the TestJoystick.java. The input started recording at values “Joy Right = 2.2655213E-4”.

At “full on” you get:



Joy Right = 0.001338542

Joy Right = 0.001338542

Joy Right = 0.001338542

Joy Right = 0.0012140265

Joy Right = 0.0012762842

Joy Right = 0.0012762842

Joy Right = 0.0012762842

Joy Right = 0.0015564442

Joy Right = 0.0015564442

Joy Right = 0.0015875731

Joy Right = 0.0016809597

Joy Right = 0.0016809597

Joy Right = 0.0016809597

Joy Right = 0.001618702

Joy Right = 0.001649831

Joy Right = 0.001618702

Joy Right = 0.0015875731

Joy Right = 0.001618702

Joy Right = 0.0015875731

Joy Right = 0.0015875731

Joy Right = 0.0012327092

Joy Right = 0.0012327092

Joy Right = 0.0012327092

Joy Right = 0.0012085384

Joy Right = 0.0012327092



As you can see these values are all over the place, not to mention rather small compared to the way other game engines report these values (usually ranging from 0-1).

Any ideas? Thanks.

edit:

This is on Win7 x64 with jme3 nightly. The joystick is working correctly with Windows.

You really think this is just broken and nobody noticed? :slight_smile: You are interpreting the values wrong, they are dependent on both the framerate and the accuracy of your hardware. The values are basically the input value multiplied with tpf, so its already framerate-adapted.

Okay, thanks. That makes sense.



Is this the correct way?



[java]

public void onAnalog(String name, float value, float tpf)

{

if (name.equals("Joy Left"))

{

float steering = value / tpf;

player.steer(steering);

System.out.println(name + " = " + steering);

}

}

[/java]

I assume that is the correct way but I’m still getting inconsistent input recognition.

For example, sometimes “Joy Left” or “Joy Right” doesn’t get activated when moving the joysticks (ie can’t steer).

[java]

private void setupKeys()

{

inputManager.addMapping(“Joy Left”, new JoyAxisTrigger(0, 1, true));

inputManager.addMapping(“Joy Right”, new JoyAxisTrigger(0, 1, false));



inputManager.addListener(this, “Joy Left”);

inputManager.addListener(this, “Joy Right”);

}



public void onAnalog(String name, float value, float tpf)

{

float adjustedValue = value / tpf;



if (name.equals(“Joy Left”))

{

player.steer(adjustedValue * .5f);

}

if (name.equals(“Joy Right”)) // I’ve tried using “else if” as well

{

player.steer(-adjustedValue * .5f);

}

}

[/java]



It’s almost as if the inputManager (or input listener) misses the initial input. Then I have to let off the joystick (or turn the joystick the opposite way) and then turn back to get the input recognized.



Is there ever a case where you should have more than one input listener? Would this catch more inputs?

I downloaded and installed Mad Skills Motocross to test if my controller was working with a jME game and it works fine. There must be something wrong with my implementation but I just can’t figure it out.



I started over and added just the bare minimum of code to test the joystick. I started with the TestJoystick.java and added a cube that would spin on input from the X axis. I still get the lost inputs in this minimal scenario. When changing from -x to x (left to right) sometimes it doesn’t pick up the new input. It seems random in occurrence but it happens often (1 out of 5 changes in input). It’s almost as if the engine is busy while the input happens so the input doesn’t get read.



Has anyone else experienced this?

Upon looking at the documentation again, it appears I wasn’t interpreting the values incorrectly, at least according to the docs.



The following is the code from the tutorial:

[java]

private AnalogListener analogListener = new AnalogListener() {

public void onAnalog(String name, float value, float tpf) {



if (name.equals(“Rotate”)) { // test?

player.rotate(0, value*speed, 0); // action!

} // else if …



}

};

[/java]



That matched my original code (since I got it from that tutorial). The question that I have is, how are they using an input as inconsistent as the values I posted in the original post? Am I correct to multiply the values by “tpf”. That seemed to at least give me a consistent input when the inputs were being picked up.



Regardless of multiplying by “tpf” or not I still get the missed inputs.



I must be missing something.

Can you try printing out some message when each of those bindings is invoked? Then it wont matter how you’re multiplying it, you should still see something

Thanks for the tip Momoko, but that’s how I know it’s not working correctly. I made a quick video of the problem. (framerate of video stinks thanks to CamStudio and/or my PC)



http://www.youtube.com/watch?v=_EIo3RoEC9s



Here is what the code used in that video looks like:
[java]
public void onAnalog(String name, float value, float tpf)
{
adjustedValue = value / tpf;

if (adjustedValue < .25f)
{
adjustedValue = 0;
}

if (name.equals("Joy Left") && value > .006f)
{
player.steer(.5f); //adjustedValue * .5f); // using this instead of value or adjusted value for troubleshooting purposes
System.out.println(name + " = " + value);
}
else if (name.equals("Joy Right") && value > .006f)
{
player.steer(-.5f); //adjustedValue * .5f);
System.out.println(name + " = " + value);
}
else
{
player.steer(0);
}
}
[/java]

Thanks for looking! :)

According to your video this line is being executed even when the turning doesn’t work properly:

[java]

else if (name.equals(“Joy Right”) && value > .006f)

{

player.steer(-.5f); //adjustedValue * .5f);

System.out.println(name + " = " + value);

}

[/java]



Could mean it’s something wrong with your player.steer() method?

It must be but that isn’t my method. It’s a jME method accessed through VehicleControl (aka player).

Actually it can’t be the steer method that’s the problem. The same thing happens in the minimal demo I made with the spinning cube. It’s got to be the input listener.



This is driving me nuts!

If you post up the minimal demo with the cube I can give it a go… though I do hope it doesn’t drive me insane also!

I’ve tried using the joystick in the TestFancyCar test and it worked fine for me. Here’s the code I used:

[java] if (binding.equals(“Lefts”)) {

player.steer(value / tpf);

} else if (binding.equals(“Rights”)) {

player.steer(-value / tpf);

} else if (binding.equals(“Ups”)) {

player.accelerate(-800 * value / tpf);

}[/java]

The issue with doing it that way is that once that analog input is no longer activated, the vehicle will keep doing whatever the last steer or accelerate call told it to do. You need to have some code called on update that will check if your AnalogListener has been activated for steering and acceleration, and if not, then set the appropriate value to zero.

That would be very awesome of you.



Just steer left and right on the joystick. It seems to miss inputs more if they are quick turns from full left to full right or vice versa.



Here’s the code:



[java]

package jme3test.app;



import com.jme3.app.Application;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;



import com.jme3.input.Joystick;

import com.jme3.input.controls.AnalogListener;

import com.jme3.input.controls.JoyAxisTrigger;



import com.jme3.system.AppSettings;



public class TestBareBonesApp extends Application

{

private Geometry boxGeom;

float speed = 0;



public static void main(String[] args)

{

TestBareBonesApp app = new TestBareBonesApp();

AppSettings settings = new AppSettings(true);

settings.setUseJoysticks(true);

app.setSettings(settings);

app.start();

}



@Override

public void initialize()

{

super.initialize();



boxGeom = new Geometry(“Box”, new Box(Vector3f.ZERO, 2, 2, 2));

boxGeom.setMaterial(assetManager.loadMaterial(“Interface/Logo/Logo.j3m”));

viewPort.attachScene(boxGeom);



Joystick[] joysticks = inputManager.getJoysticks();

if (joysticks == null)

{

throw new IllegalStateException(“Cannot find any joysticks!”);

}

for (Joystick joy : joysticks)

{

System.out.println(joy.toString());

}

inputManager.addMapping(“Joy Left”, new JoyAxisTrigger(0, 1, true));

inputManager.addMapping(“Joy Right”, new JoyAxisTrigger(0, 1, false));

inputManager.addListener(analogListener, “Joy Left”);

inputManager.addListener(analogListener, “Joy Right”);



System.out.println(“Initialized”);

}



private AnalogListener analogListener = new AnalogListener()

{

public void onAnalog(String name, float value, float tpf)

{

float adjustedValue = value/tpf;

if (name.equals(“Joy Left”) && adjustedValue > .25f)//value > .0005f)

{

speed = -.5f;

System.out.println(name + " = " + value);

}

else if (name.equals(“Joy Right”) && adjustedValue > .25f)//value > .0005f)

{

speed = .5f;

System.out.println(name + " = " + value);

}

else

{

speed = 0;

}

}

};



@Override

public void update()

{

super.update();



// do some animation

float tpf = timer.getTimePerFrame();

boxGeom.rotate(0, speed*tpf, 0);



// dont forget to update the scenes

//boxGeom.updateLogicalState(tpf);

boxGeom.updateGeometricState();



// render the viewports

renderManager.render(tpf, context.isRenderable());

}



@Override

public void destroy()

{

super.destroy();



System.out.println(“Destroy”);

}

}

[/java]



Disclaimer: Not responsible for temporary losses of sanity resulting from running this application



Thanks!

Thanks for looking into it Momoko Fan. Did you use a joystick when you tested that? That code is basically where I started from. I’ve tried every different angle of attack I could think of to get the inputs but none of them are successful.



I popped that code into my test apps and I’m still having the same issue. It makes it down into the ifs and else ifs, it prints out my messages but it doesn’t turn the wheels using the axis value (or turn the cube by setting speed to a value, etc).



It is very strange and something that seems like it may turn out to be something special that happens just for me. ;p (although I did catch it on video so I know I’m not crazy)

Hello, I got the same problem as you, now we are both crazy :slight_smile:



I found out some more info though. By adding this:

[java]

else

{

speed = 0f;

System.out.println("NOT WELCOME HERE:: " + name + " :: " + value + " :: " + tpf);

}

[/java]

When you get the ‘locked out’ left value, you can now see why. Here is the output when the left direction doesn’t seem to work anymore:

[java]

LEFT = 3.1250002E-4

NOT WELCOME HERE:: Joy Right :: 2.1672586E-5 :: 3.1250002E-4

LEFT = 2.8125002E-4

NOT WELCOME HERE:: Joy Right :: 1.9505327E-5 :: 2.8125002E-4

LEFT = 2.8125002E-4

NOT WELCOME HERE:: Joy Right :: 1.9505327E-5 :: 2.8125002E-4

[/java]



You get immediate back to back calls, one to left and one to right! Bizarre, since you are holding left on the joystick. I will look into a bit and see if I can find out why



For the record, you can also ‘lock out’ holding Right as well

[java]

RIGHT = 5.0E-4

NOT WELCOME HERE:: Joy Left :: 3.131914E-5 :: 5.0E-4

RIGHT = 4.6875002E-4

NOT WELCOME HERE:: Joy Left :: 2.9361696E-5 :: 4.6875002E-4

RIGHT = 5.0E-4

NOT WELCOME HERE:: Joy Left :: 3.131914E-5 :: 5.0E-4

[/java]



Also you can get it to send large the double messages with large values, not just near zeros. For instance, this is the output I get while holding right after doing a quick left-right combo

[java]

LEFT = 9.835775E-5

RIGHT = 3.4375003E-4

LEFT = 9.016127E-5

RIGHT = 3.4375003E-4

LEFT = 9.016127E-5

RIGHT = 3.4375003E-4

[/java]

1 Like

Wow, bigstink! Great info there. I’ll play with that a bit.



Is there a way to go back to stable after you go to nightlies? I’d like to try this out on the stable version available to download but I don’t want to uninstall everything.

So, if that example above is correct and since this is happening to more than one person, can we say that this issue is a bug?

I was able to reproduce it by quickly shifting the control stick from left to right. The reason the bug occurs is because the binding for the other side of the axis is not reset unless it enters the dead zone. I now fixed it so it is reset always.

1 Like

Thanks for the change Momoko Fan! That works like a charm. And thanks again to bigstink for confirming the problem for me.