ArturSpirin/pyPS4Controller

at rest event triggering too often

ArminBmrt opened this issue · 4 comments

Hi,

I am trying to get some simple analog values from the controller. The values are x (up/down) and y (left/right) and these values should also be zero when released.

Output from my test move is below: I move the left joystick to its maximum right position and a bit up. When I slowly move the joystick lower the at rest event is triggered when the x is zero. The problem is only one axis is at rest, the other one still has some input.

In my code I set both x and y to zero when at rest. This does not work because only x is zero and y still has a value. When I remove the at rest event the output is never zero

Is this the intended behaviour and how is it possible to get the correct output?

Output from a test run:

Waiting for interface: /dev/input/js0 to become available . . .
x: 0.00 y: 0.00
Successfully bound to: /dev/input/js0.
x: 0.00 y: 0.00
x: 0.00 y: 0.00
x: 0.00 y: 0.00
x: 0.00 y: 0.00
x: 0.54 y: 1.00
x: 0.18 y: 1.00
x: 0.10 y: 1.00
At rest
x: 0.00 y: 0.00
x: 0.00 y: 0.00
At rest
At rest
x: 0.00 y: 0.00
x: 0.00 y: 0.00
x: 0.00 y: 0.00
x: 0.00 y: 0.00
x: 0.00 y: 0.00
^CTraceback (most recent call last):
  File "./test.py", line 62, in <module>
	time.sleep(0.5)
KeyboardInterrupt

My test code:

#!/usr/bin/python3
import threading
import time
from pyPS4Controller.controller import Controller
from pyPS4Controller.controller import Event


class MyController(Controller):
	def __init__(self, **kwargs):
		Controller.__init__(self, **kwargs)
		self.scale = 32767
		self.x = 0.0
		self.y = 0.0

	def start(self):
		self.start_thread = threading.Thread(target=self.run, args=())
		self.start_thread.daemon = True  # Daemonize thread
		self.start_thread.start()
		# Auto setup connection and start thread and stuff

	def run(self):
		while True:
			self.listen()
			self.stop_motion()
			print('listen exit, should not happen')
			time.sleep(1)

	def stop_motion(self):
		self.x = 0.0
		self.y = 0.0

	def on_connect_callback(self):
		super()
		print('Hoi on_connect_callback event')

	def on_disconnect_callback(self):
		print('Hoi on disconnect event')

	def on_L3_up(self, value):
		self.x = value / self.scale

	def on_L3_down(self, value):
		self.x = value / self.scale

	def on_L3_left(self, value):
		self.y = value / self.scale

	def on_L3_right(self, value):
		self.y = value / self.scale

	def on_L3_at_rest(self):
		self.x = 0.0
		self.y = 0.0
		print('At rest')


controller = MyController(interface="/dev/input/js0", connecting_using_ds4drv=False, event_format="3Bh2b")
controller.start()

while True:
	print(f'x: {controller.x:.2f} y: {controller.y:.2f}')
	time.sleep(0.5)

Hey Artur, could you please make a quick edit so that the button_id of the joystick is returned with the R3_at_rest() and L3_at_rest() in your event handler. That way we can distinguish between the horizontal and vertical joystick rest positions.

I hacked it quickly just to test. I copied controller.py to my own project. I forgot to commit until all changes were done so I do not have a diff.

I basically replaced the L3 events with two of my own in the listen method of the Controller class

elif event.L3_event():
	if event.button_id == 1:
		self.on_L3_up_down(value)
	elif event.button_id == 0:
		self.on_L3_left_right(value)
	# if event.L3_at_rest():
	#     self.on_L3_at_rest()
	# elif event.L3_up():
	#     self.on_L3_up(value)
	# elif event.L3_down():
	#     self.on_L3_down(value)
	# elif event.L3_left():
	#     self.on_L3_left(value)
	# elif event.L3_right():
	#     self.on_L3_right(value)

And when inheriting the class I override these fuctions with:

def on_L3_up_down(self, value):
    self.x = -value / self.scale

def on_L3_left_right(self, value):
    self.y = value / self.scale

This gives me a value between -1 and 1 for each axis. For my application this makes more sense than a up,down,left,right event.

@ArminBmrt I see the issue. Looks like both axis will trigger the at rest events.

...
    def L3_at_rest(self):
        return self.button_id in [1, 0] and self.value == 0
...

I'll look into splitting that event into two separate events for each axis.

@ArminBmrt Pushed a fix to dev branch, unfortunately I do not have anywhere to test the fix on right now, if you can confirm its working - I can push it to master and deploy new version to Pypi.