Skip to content
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

Support: Impulse Triggers #23

Closed
atar-axis opened this issue Mar 8, 2018 · 49 comments
Closed

Support: Impulse Triggers #23

atar-axis opened this issue Mar 8, 2018 · 49 comments
Labels
0 | type: enhancement New feature or request 1 | state: testing solution Solution is in testing phase

Comments

@atar-axis
Copy link
Owner

atar-axis commented Mar 8, 2018

While searching for a way to dim the Xbox-Logo light i explored another feature:

R2 and L2 are able to give some force feedback too, not sure how we should implement that
but it's funny as hell 😄

@kakra
Copy link
Collaborator

kakra commented Mar 8, 2018

I think directional rumble should also be possible...

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 8, 2018

Documentation: FF report (ID 03)

<--- MSB/MSb --- LSB/LSb ---

LLLL LLLL SSSS SSSS DDDD DDDD 4444 4444 3333 3333 2222 2222 1111 1111 XXXX EEEE

E - Enable Actuators

0x01: Rumble Right
0x02: Rumble Left
0x04: Impulse Trigger Right
0x08: Impulse Trigger Left

X - Padding

1 - Magnitude

Impulse Trigger Left

2 - Magnitude

Impulse Trigger Right

3 - Magnitude

Rumble Left

4 - Magnitude

Rumble Right

D - Duration

In seconds*10^-2 = 0,01s

S - Start Delay

In seconds*10^-2 = 0,01s

L - Loop Count

How often should we repeat the effect

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 8, 2018

I think directional rumble should also be possible...

Not over BT i fear - since the HID output report 03 is exhausted now (previously i thought the other bits are reserved)

@atar-axis atar-axis changed the title Support: L2 and R2 rumble Support: Impulse Triggers Mar 8, 2018
@atar-axis atar-axis added 0 | type: enhancement New feature or request information needed Some additional information is needed labels Mar 8, 2018
@kakra
Copy link
Collaborator

kakra commented Mar 9, 2018

I don't know the interfaces, but since we have left and right rumble, directional rumble is possible. In wine joy.cpl I see that you can set a direction for rumble effects.

@atar-axis
Copy link
Owner Author

ah i see - directional in the sense of right/left! yes, thats for sure possible! :)

what i thought you mean is if the force pulls/pushes into a specific direction

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 12, 2018

struct ff_effect {
	__u16 type;
	__s16 id;
	__u16 direction;
	struct ff_trigger trigger;
	struct ff_replay replay;

	union {
		struct ff_constant_effect constant;
		struct ff_ramp_effect ramp;
		struct ff_periodic_effect periodic;
		struct ff_condition_effect condition[2]; /* One for each axis */
		struct ff_rumble_effect rumble;
	} u;
};  
struct ff_rumble_effect {
  __u16 strong_magnitude;
  __u16 weak_magnitude;
};  

Unfortunately I fear there is no impulse trigger support at the moment (at the linux kernel). Furthermore, the directional effect does not really make sense at the Xbox One Wireless Controller since both sides (left/right) do only offer one of both effects (strong rumble/weak rumble). They rumble hardware is not equal.

But maybe I overlooked something, I will dig a bit deeper.

@kakra
Copy link
Collaborator

kakra commented Mar 12, 2018

I don't think that impulse trigger should be a rumble effect but instead a force feedback effect... Does Linux support force feedback (I mean, really applying counter force instead of playing just rumble effects) - then that would be the way to go.

BTW: This feature isn't even supported by the Windows driver as far as some research shows. And the Steam community is full of posts about alternative drivers which support more Xbox controller features than the one MS provides in Windows.

https://www.youtube.com/watch?v=G4PHupKm2OQ

@kakra
Copy link
Collaborator

kakra commented Mar 12, 2018

I think directional feedback should go as far as giving me feedback in a shooter if I'm hit from left or right. This is probably up to the game, as long as the interface is provided.

Impulse triggers would be interesting for features like the shock when pulling the trigger to fire your weapon, or for driving simulations by sending feedback from the wheels or the motor. Also see previous youtube link.

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 12, 2018

I don't think that impulse trigger should be a rumble effect but instead a force feedback effect... Does Linux support force feedback (I mean, really applying counter force instead of playing just rumble effects) - then that would be the way to go.

Well, as far as I know rumble is just a special kind of force feedback, at least in the sense the kernel handles it.

The kernel does in fact support a bunch of FF effects, those are:

FF_CONSTANT can render constant force effects
FF_PERIODIC can render periodic effects with the following waveforms:
  FF_SQUARE square waveform
  FF_TRIANGLE triangle waveform
  FF_SINE sine waveform
  FF_SAW_UP sawtooth up waveform
  FF_SAW_DOWN sawtooth down waveform
  FF_CUSTOM custom waveform
FF_RAMP can render ramp effects
FF_SPRING can simulate the presence of a spring
FF_FRICTION can simulate friction
FF_DAMPER can simulate damper effects
FF_RUMBLE rumble effects
FF_INERTIA can simulate inertia
FF_GAIN gain is adjustable
FF_AUTOCENTER autocenter is adjustable

(take a look here)

But none of those does really fit, right? To be honest, it is just a rumbling motor, so something like FF_RUMBLE_TRIGGER would be best, but it does not exist (at the moment).

Our best bet seems to be FF_CONSTANT, since this seems to be the only one which is at least implemented in some drivers (but mostly wheels).
Is this what you meant? Something like the counterforce while driving?
It is not really a counterforce but yeah, the idea is somehow the same and it could be fun at car games I think ^^

Another solution would be to let the triggers rumble whenever the "normal" rumble occurs. What would you, as a gamer, prefer?

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 12, 2018

I think directional feedback should go as far as giving me feedback in a shooter if I'm hit from left or right. This is probably up to the game, as long as the interface is provided.

Ah, mhm, for a short period it is okay I think. But a shot from the left feels a bit different than one from the right then ;D

We would need two rumble motors (a weak one and a strong one) on both sides to fit the structure as it is in the kernel.

Where is why:
The FF_RUMBLE interface does offer you to set those properties separately. You can say you want a bit of a strong rumble and much of the weak at the same time at the left hand, and nothing at the right.

In practice this isn't possible - since most gamepads only have two rumble motors, one is the weak one, the other one is the strong one - and they are placed like: weak -> right handle, strong -> left handle (or vice versa).

Therefore, we totally ignore the left/right directional property until now.

Imagine the game requests a rumbling effect on the left using the motor (weak/strong) which is on the right - how should we do that? The only thing we could do then is to approximate the effect magnitude using the wrong motor (if a bit of strong rumbling is requested on the side where the weak motor is, then we could rumble a bit harder using the weak one). But yes, it is just an approximation then.

Again @kakra: What do you think, should we prefer to offer directional effects or to be more precise?

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

The Steam controller is pretty capable of emulating most of the effects. It doesn't have rumbling motors but small magentic accelerators that work like in a sound speaker, and for different directions. This is why the effect is very subtle and makes sounds. But if you flip the finger across the touch pad, it feels like a track ball is rotating with inertia, and when you stop it, you can feel that stopping shock, too. It has friction effects when you program a pad with virtual buttons. The triggers have a non-programmable hardware trigger point near the end (with some higher, clicking force). The Steam input driver can try to emulate many effects, but it's far from rumble.

For the Xbox controller I could also think of FF_SPRING could be a usable effect. But without ever experiencing it, I cannot really help here. Do you have a test program which could play the trigger effects built into the controller?

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

Ah, here I see what you mean: https://zh.ifixit.com/Guide/Xbox+One+Wireless+Controller+Trigger+Rumble+Motor+Replacement/36558

So, essentially the problem is that we have only two axis in the interface to apply FF effects to?

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

BTW: From the pictures, it looks to me like the strong motors are left and right in the grips, and the weak motors in the triggers. Also, when I opened my F710, it had two identical motors on each side. Can you just turn the motors on and off, or is it possible to apply a value for rotation speed?

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

I just found that there's ffmvforce and ffcfstress additionally to fftest. While the former does nothing, the latter claims the controller has no support.

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 13, 2018

I just found that there ffmvtest and ffcfstress additionally to fftest. While the former does nothing, the latter claims the controller has no support.

I didn't knew about the others but I always used/use fftest here, and it is still working for me:

fftest /dev/input/event14
Force feedback test program.
HOLD FIRMLY YOUR WHEEL OR JOYSTICK TO PREVENT DAMAGES

Device /dev/input/event14 opened
Features:
  * Absolute axes: X, Y, Z, RX, RY, RZ, Hat 0 X, Hat 0 Y, 
    [3F 00 03 00 00 00 00 00 ]
  * Relative axes: 
    [00 00 ]
  * Force feedback effects types: Periodic, Rumble, Gain, 
    Force feedback periodic effects: Square, Triangle, Sine, 
    [00 00 00 00 00 00 00 00 00 00 03 07 01 00 00 00 ]
  * Number of simultaneous effects: 16

Setting master gain to 75% ... OK
Uploading effect #0 (Periodic sinusoidal) ... OK (id 0)
Uploading effect #1 (Constant) ... Error: Invalid argument
Uploading effect #2 (Spring) ... Error: Invalid argument
Uploading effect #3 (Damper) ... Error: Invalid argument
Uploading effect #4 (Strong rumble, with heavy motor) ... OK (id 1)
Uploading effect #5 (Weak rumble, with light motor) ... OK (id 2)
Enter effect number, -1 to exit

From the pictures, it looks to me like the strong motors are left and right in the grips, and the weak motors in the triggers. Also, when I opened my F710, it had two identical motors on each side. Can you just turn the motors on and off, or is it possible to apply a value for rotation speed?

For every kind of effect, you can set a direction:

  • 0 deg -> 0x0000 (down)
  • 90 deg -> 0x4000 (left)
  • 180 deg -> 0x8000 (up)
  • 270 deg -> 0xC000 (right)

Furthermore, there are effect-specific properties. For the FF_RUMBLE effect, you can also set:

  • strong_magnitude (left grip), 0 to 0xFFFF
  • weak_magnitude (right grip), 0 to 0xFFFF

That's the software part. The hardware looks like the following:

We have three kinds of motors:

  • a strong one, which is in the left grip
  • a not-so-strong one, which is in the right grip
  • two very small ones at the triggers

You can see the difference between the grip-motors (the weights) here.

We can set a "rotational speed" for all four motors independently.


Given that information, how would you handle an effect request, which wants:

  • direction: right
  • strong_magnitude: 0x80FF
  • weak_magnitude: 0x0000

The strong motor is on the left, but the direction requests an effect on the right side...^^
As I said above, the only way to offer both - directional effects and the normal RUMBLE thing, is appoximation in my eyes. I think that's most probably what most drivers do (unchecked).


For the Xbox controller I could also think of FF_SPRING could be a usable effect. But without ever experiencing it, I cannot really help here. Do you have a test program which could play the trigger effects built into the controller?

You mean experiencing the Impulse Trigger thingy? I can simply implement first support and we can decide on how exactly the interface should look like later - then you can test it too.

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

It would make sense to have this test program when it could somehow access the trigger motors. It would be nice if it supported raw access to the functions so we could experiment with it. Is it possible to bypass the hid driver and access hidraw for this?

I could think of this solution:

Depending on the direction (left or right), not just play the strong or weak motor, but also the left or right trigger motor. If direction is forward, play both trigger motors. If backward, play no trigger motor but just the weak or strong motor. What do you think?

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

BTW: Interesting... If I put the controller on the table and push down on the left grip only with a finger tip, playing the strong effect creates a strong pull to the right. Pushing down on the other side, it just wobbles. Can we exploit that somehow? ;-)

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 13, 2018

It would make sense to have this test program when it could somehow access the trigger motors. It would be nice if it supported raw access to the functions so we could experiment with it. Is it possible to bypass the hid driver and access hidraw for this?

I will give it a try and report back.

Depending on the direction (left or right), not just play the strong or weak motor, but also the left or right trigger motor. If direction is forward, play both trigger motors. If backward, play no trigger motor but just the weak or strong motor. What do you think?

That's indeed a very clever but still a bit dirty solution.
The only really clean one is to change even more kernel code, I fear. I think I will write Vojtech Pavlik (the author of the input subsystem) an eMail - he probably knows it the best.

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

Let's be dirty then... ;-)

Even if kernel interfaces changed, it will take time for games to adapt. So this dirty solution would be some sort of "legacy" mode. And we can add a modern mode later and expose that as a configurable module parameter so you can choose which interface suits your needs.

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

It would make sense to have this test program when it could somehow access the trigger motors. It would be nice if it supported raw access to the functions so we could experiment with it. Is it possible to bypass the hid driver and access hidraw for this?

I will give it a try and report back.

If you provide the basic framework, I could add the rest of the code to it.

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 13, 2018

Okay, as a temporary solution 😄 as long as there is no better kernel-support.
To sum it up: We will use the directional information for the trigger-motors for now.

Therefore the strength of the rumble at the right/left trigger will be influenced by two factors:

  1. direction of the effect
    • right -> right trigger
    • forward -> both triggers
    • left -> left trigger
    • backwards -> none
  2. magnitude of the strong motor
    • the magnitude of the effects played at the triggers are proportional to the magnitude of the effect played on the strong motor

Agreed?

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

Sounds fine, I was already thinking about it.

As far as I can see, we can play the strong and weak motor independent of each other or at the same time, with a magnitude of 0 to 100% each. We should stick with a 1:1 mapping here to not change how games expect it to work.

Now we emulate a direction. The further up the direction points, the stronger the magnitude. Point north should play both trigger motors at 100%. I think you'll need sine/cosine tables for it. But we can make it linear first and see if that easy solution works well enough.

What do we do with the south direction? Should we map the complete Y axis of the circle to 0 to 100% (from bottom up), or just the upper half of the circle, and let the lower half just not play the triggers at all? I think the latter implementation could make more sense since the triggers are in the front only. The lower half could instead bias the grip motors instead. But we should not do this in the first implementation as it could violate games expectations.

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 13, 2018

As far as I can see, we can play the strong and weak motor independent of each other or at the same time, with a magnitude of 0 to 100% each. We should stick with a 1:1 mapping here to not change how games expect it to work.

That's correct! What do you mean by 1:1 mapping?

Now we emulate a direction. The further up the direction points, the stronger the magnitude. Point north should play both motors at 100%. I think you'll need sine/cosine tables for it. But we can make it linear first and see if that easy solution works well enough.

Maybe not at 100% but at most as strong as e.g. the strong motor is playing? What do you think? Would be a bit strange it the Triggers are rumbling more than the Gampad itself.

What do we do with the south direction? Should we map the complete Y axis of the circle to 0 to 100% (from bottom up), or just the upper half of the circle, and let the lower half just not play the triggers at all? I think the latter implementation could make more sense since the triggers are in the front only.

I agree, I would also go fot the latter one.

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

This latter solution has the advantage that you can play rumble without triggers by just pointing backward. Otherwise we would always have triggers rumble with no chance to prevent that.

1:1 means keep it how it works currently, not influenced by direction.

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

0 = 0x0000, 2 = 0x2222 etc

0 to 4 and C to F map both trigger motors to off.
4 to 6 maps trigger left to 0-100%, right to 0%
6 to 8 maps trigger left to 100%, right to 0-100%
8 to A maps trigger left to 100-0%, right to 100%
A to C maps trigger left to 0%, right to 100-0%
Playing weak or strong only chooses the grip motors, no effect on trigger magnitude.

This way it should be possible to play every combination of magnitude with every motor, right?

It should even be possible to rumble the triggers only by sending a magnitude of 0 to the grip motors.

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 13, 2018

1:1 means keep it how it works currently, not influenced by direction.

I see, yes for sure - the direction will only influence the "new" trigger buttons. Everything else stays as normal.

Playing weak or strong only chooses the grip motors, no effect on trigger magnitude.

Imagine that a game invokes an super-duper light effect on the left. This way (which you mentioned) the gamepad would play a very strong effect at the left trigger, which is way stronger than the main-rumbling which was requested. I therefore think that the grip-magnitude (which is the only we have) should influence the triggers too.

So my suggestion would be:

0 to 4 and C to F map both trigger motors to off.
4 to C maps trigger left to 100-0%, right to 0-100%, with 50%/50% at 8

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

I hope I find a game to test that... ;-)

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

Playing weak or strong only chooses the grip motors, no effect on trigger magnitude.
Imagine that a game invokes an super-duper light effect on the left. This way (which you mentioned) the gamepad would play a very strong effect at the left trigger, which is way more strong than the main-rumbling which was requested. I therefore think that the grip-magnitude (which is the only we have) should influence the triggers too.

Maybe we could add a trigger_bias module parameter which sets how much the trigger motors are influenced by the grip motor magnitude. But if weak and strong play at the same time: Which magnitude will you choose?

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

Maybe the choosen magnitude should not be a multiple of all magnitudes and a bias how I first imagined but simply a max of (weak,strong,directional). A module parameter then instead chooses if this max() value is used or if only directional is used.

@atar-axis
Copy link
Owner Author

Maybe we could add a trigger_bias module parameter which sets how much the trigger motors are influences by the grip motor magnitude.

For sure, that's not a problem.

But if weak and strong play at the same time: Which magnitude will you choose?

Maybe something like max{strong,weak}, I think that's something we will have to evaluate then.

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

Ah yes, max(weak,strong)*directional makes more sense ;-)

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

Or min(directional,max(weak,strong))...

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 13, 2018

Ah yes, max(weak,strong)*directional makes more sense ;-)

Perfect! Let's do it like that - it's easy to change afterwards if it does not work as expected ;) As always: Thank you very much and good night ;D

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

Looking forward, I'll now research which Linux games could support that. At least wine joy.cpl has a directional interface for rumble. Maybe you could look at the source and see if and how it translates that to Linux... Then, I could try games in Wine. I'm not sure if one of the pseudo-native Linux games would support directional rumble.

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

Looks like DIRT, GRID and Eurotruck Simulator 2 have support for directional FF. Tho, it may be used for centering the steering wheel. At least, I believe I have all three in my Steam library as native Linux games.

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 13, 2018

pushed a first version which enables the other two motors, will do the math tomorrow (later). At least you can experience it with fftest now! Night! ;)

Btw: The magnitude for the triggers are downscaled to a fourth(!)

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

Aw well, night time for me, too.

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 13, 2018

in addition to the commit above i've added a very very basic test tool.
next steps:

  • replace the LUT by a simple and (more) continuous calculation
  • transfer the magic 4 in (u8)(((max / 4) * proportion_left_trigger) / 1000); to a parameter (gain)
  • (extend the test program)
  • clean up

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 13, 2018

fullsizerender

@kakra: this is what you are talking about, right?

edit: ups, alpha should be alpha = (180 / 0x8000) * value - 90
edit2: damn it, my math teacher would kill me... mixed up left and right too xD

@kakra
Copy link
Collaborator

kakra commented Mar 13, 2018

Yes, tho I don't think we need curve functions. We can simply make it linear per each 45 degrees - at least for the start.

Then a series of if clauses just does the math:

if x in 0x0000...0x4444 or x in 0xCCCC...0xFFFF then directional = { left: 0, right: 0 }
if x in 0x4444...0x6666 then directional = { left: (x-0x4444)/0x2222, right: 0 }
if x in 0x6666...0x8888 then directional = { left: 1, right: (0x8888-x)/0x2222 }

You get the idea... Pseudo code, "..." meaning non-inclusive (as in Ruby). The 0xFFFF check has to do an inclusive check. Or better, it checks against 0x10000, as actually the 0x1111 are endless fractionals and in that definition 0xFFFF does not exist. This is the fraction of 1/9, which makes 0.11111..., 0.22222... and so on but 0.999999... does not exist: It's equal to 1.

Does it make sense? The circle has four or eight slices which is perfectly easy to do with a hexadecimal radial scale. How did I think we need to use 0x2222 etc? Well, whatever, the idea is the same.

PS: I should have drawn the complete circle with slice 0-F instead of only the upper half 4-C, then I would have seen my error. Go with 0x2000, 0x4000 instead. ;-)

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 13, 2018

ef8d113
Used an cosine LUT, think this is the easiest and best looking way - but you're right, feels better now

@atar-axis
Copy link
Owner Author

atar-axis commented Mar 13, 2018

I've added the parameter trigger_rumble_damping (0 to 8, non-linear), so in theory it is ready 😃
Will close this issue within 24 hours if everything seems to be fine.

@kakra
Copy link
Collaborator

kakra commented Mar 14, 2018

Let me test this, hopefully today or tomorrow.

atar-axis added a commit that referenced this issue Mar 14, 2018
…tnumber)

* changed damping parameter to 4 and made it linear

see #23
@atar-axis atar-axis added 1 | state: testing solution Solution is in testing phase and removed information needed Some additional information is needed labels Mar 14, 2018
@atar-axis
Copy link
Owner Author

atar-axis commented Mar 14, 2018

I've added an test program yesterday, at least here it works
./directional_rumble_rest <eventnumber> [<magnitude, 0 to 65535>]
Im curious how it feels ingame :game:

@atar-axis
Copy link
Owner Author

@kakra have you found any native linux game that supports directional rumble? :)

@kakra
Copy link
Collaborator

kakra commented Mar 23, 2018

Not yet, or at least I didn't sense it doing so. But I found that sometimes, FF effects play, and sometimes they don't. Usually, that's pretty consistent throughout the gameplay: When it's missing from the start, FF usually never plays. When it works, it sometimes misses playing FF effects when there should be effects. I'm yet to figure this out better. It's somehow similar to how my modified test program plays only the first round of effects...

@kakra
Copy link
Collaborator

kakra commented May 6, 2018

I didn't yet came across a game that uses directional rumble. The rumble effects sometimes missing didn't occur in a while. It's consistently working in games currently.

@atar-axis
Copy link
Owner Author

atar-axis commented May 8, 2018

Thank you for getting back 👍

@atar-axis
Copy link
Owner Author

Closing - works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0 | type: enhancement New feature or request 1 | state: testing solution Solution is in testing phase
Projects
None yet
Development

No branches or pull requests

2 participants