-
-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug] XboxController joystick reporting nonzero values after release #1473
Comments
This is known as controller drift in the gaming community. The joysticks don't go all the way to the perfect zero due to mechanical friction. In some upcoming examples, I've added an if/else check to ignore very small inputs. Since the motors don't run great at very low speeds, this would probably have been needed anyway, depending on the application. As I write this, I suppose we could add some code to make small inputs always zero for simplicity. Would this be desirable? What should be the threshold? Maybe it could be a keyword argument defaulting to 10%? Or 5%? |
On a windows pc you can install "Xbox accessories". In my case a default of 5 would be enough most of the time. Sometimes they stick at 6 or seven, but a nudge keeps them within -5 and 5. I would like that threshold very much. Thanks you. Bert |
Oh, I see
Yes, that's what I did in my code as well, but it would be nice if I didn't have to do that in every program for every joystick
5% worked also for me, I think that's a good value for a default. It could be a keyword argument like |
Does this affect the numbers in Pybricks too? I'm asking because it's possible that this sets other mapping values on the controller that we might not currently use. With a Spike Hub or Robot Inventor hub you will stay connected, so you could print values to find out. |
I already did that. For fun I had the xbox controller connected to a Technichub that transmits buttons and such to the robot inventor that printed to the beta.pybricks.com |
I meant that I was wondering if the zero return was better in Pybricks if you changed the controller configuration like you did. |
I've done some more experimenting, and I suppose that the deadzone rounding to 0 should be a fairly good solution. You'd lose a few degrees of precision at the very center, but this is hardly noticeable even in steering applications. I'd like the default threshold to be "good enough for most things", so the block language wouldn't need an option for it. To make things better, we can ensure to round only if both coordinates are near 0 at the same time. This way we don't have to round Y in the case of (X=100, Y=3), for example. The highest value I could get my controller to stick at was 6% degrees.
I was originally thinking to add it to the joystick methods, but maybe the controller setup is a good place for it indeed. Thanks! |
While we are at it, any opinions on the resolution? We could theoretically get about 10x more steps, e.g 12.3%. Would this be useful at all? |
I think that makes sense.
I agree this could be left out of the block coding language to keep it simple. Though, maybe, if it's a constructor parameter, then it can even be included, does not clutter too much there. It's up to you.
What's the current resolution? 1%? And how is it represented, as ints or as floats? Do you mean going down to 0.1%? Wouldn't that complicate things somewhat? I mean you'd either have to represent them as floats, or in units that would be less clear to understand, i.e. would not mean percentages anymore. I am actually okay with the current resolution in terms of steering/throttle performance, and I don't think anyone could feel the difference less than 1% in the joystick position. |
The joystick values are 16 bit, so technically up to 32768 values. The triggers are 10 bit, so 0--1024. We've scaled everything to percentages for simplicity. We'll keep it that way, but we could choose to return a floating point value to keep the resolution. Indeed, so far I've found that 100 steps is enough, but I was curious about other opinions since we're going to slightly change these methods now anyway. |
Sorry I was not clear in this Laurens. I meant to say I did the recalibrate and then checked with pybricks. |
Thanks for confirming! |
I agree with Victor about the resolution. Percentage as integer is good enough, I think. |
Maybe helpfull: I asked Copilot (AI assistent) The size of the deadzone can vary depending on the specific controller and the game or application it’s being used with. What do we suggest? So I might ajust my default drift dead zone to 10% |
Interestingly, most players on the link use cross shaped deadzone. Is that the opposite of what we thought might be good above (clip one small value even if the other value is large)? I could also imagine that one making sense, although only makes a difference when one uses a joystick in both dimensions, which I rarely do with my lego builds, so cannot judge. |
My suggestion was for two dimensions. Thanks for the links! This looks like quite another rabbit hole 😄 I think a circle or square makes a bit more sense (compared to a cross shaped zone). Our main purpose is only to eliminate the effects of drift, which is what these will do. If you also want to zero out X when Y is small as in a cross, it should be easy enough to do in user code. |
The pull request here introduces a 10% deadzone to suppress drift. It is configurable, i.e. You can download the read-made firmware from the post above in a few minutes. |
Tested with spike hub and this program: from pybricks.iodevices import XboxController
from pybricks.tools import wait
print("\x1b[H\x1b[2J", end="") # clear the log
# Set up all devices.
controller = XboxController()
# The main program starts here.
while True:
print("\x1b[H", end="") # Go to top of the screen
print(f'left trigger {controller.triggers()[0]:>20}',
f'right trigger {controller.triggers()[1]:>20}')
print(f'left joystick hor {controller.joystick_left()[0]:>20}',
f'right joystick hor {controller.joystick_right()[0]:>20}')
print(f'left joystick vertical {controller.joystick_left()[1]:>20}',
f'right joystick vertical {controller.joystick_right()[1]:>20}')
print(f'D-pad {controller.dpad():>20}')
print(f'profile {controller.profile():>20}')
if controller.buttons.pressed():
print(f'Buttons pressed {str(controller.buttons.pressed()):<50}')
else:
print(f'{"Buttons pressed":<70}')
wait(250) Noticed that a joystick reported horizontal 10 if released but the vertical was less than 10. Tested with |
Could not test yet, but the name |
Updated PR based on feedback. |
Great, thanks! |
When I release the joystick on an Xbox controller, it still seems to be reporting nonzero values, even though it snaps back to the center.
Because the Technic Hub needs to disconnect to allow the Xbox controller to connect, it is a bit tricky to actually show this, because this way the joystick values cannot be printed. The way I realized this is that I was doing speed control (
motor.run(speed)
) on a PU XL motor, and even when the joystick was released, the motor was moving very slowly.To do this, first I measured the max speed (around 270 deg/s), and then set the speed proportional to the joystick position, like
motor.run(270 * (joystick / 100))
. Note, thatmotor.dc(joystick)
would not show this behavior, because of the dead zone of the motor itself, it does not start moving for small power values, but with speed control, it can move very slowly as well.The text was updated successfully, but these errors were encountered: