ArduinoJoystickWithFFBLibrary icon indicating copy to clipboard operation
ArduinoJoystickWithFFBLibrary copied to clipboard

When used, causes MASSIVE FPS drop on certain games. (but works otherwise)

Open ThePixelArtist opened this issue 2 years ago • 5 comments

Hello, I have made a code for my wheel, which works just fine, but when i turn on games like DiRT rally, Assetto Corsa or Euro truck simulator 2, it causes a massive FPS drop. before i was getting 75 FPS in DiRT, but when i just plug in the arduino it instantly jumps to 8FPS. only game that i have registered no issue with FPS what so ever is BeamNG Drive.

The weird part to me is that when i disconnect my arduino the fps jump back up instantly, but if i connect it back again it immediately slows down again to 8FPS, also mind that the arduino isnt even doing anything when i connect it, the game seeing my arduino as a wheel with force feedback is enough for it to be slown down. Also mind the force feedback is working just fine in every game mentioned, but the FPS are not

I use arduino ProMicro is anyone was wondering

ThePixelArtist avatar Jan 07 '22 18:01 ThePixelArtist

I've had no problems playing ETS2 and DiRT Rally with my wheel. (I built my wheel specifically for ETS2!) I forked this library so that I could add some minor features and fix some bugs, but I don't think I fixed anything that would have caused the problem you describe.

When you say your Arduino isn't doing anything, do you mean your loop function is literally empty? At the least, you probably need to call Joystick.sendState(); periodically. If you aren't, that's probably the problem. When the game requests the latest joystick positions, the HID joystick driver is probably trying to read the USB endpoint and NACK'ing over and over until it times out.

Here's what my loop function looks like. I rate limit it to run no faster than 1Khz, but otherwise just let it run as fast as it can.

void loop()
{
  static unsigned long last_loop_run = micros();
  const unsigned long now = micros();
  const float dt_sec = static_cast<long>(now - last_loop_run) * 1e-6f;
  if (dt_sec >= 0.001f)
  {
    last_loop_run = now;
    const long count = myLS7366.read_counter();
    const float pos = count * (-static_cast<float>(AXIS_HALF_RANGE) / COUNT_HALF_RANGE);
    pos_filter.update(pos, dt_sec);
    vel_filter.update(pos_filter.rate(), dt_sec);

    int16_t axis_pos;
    float hardstop_dc = 0.0f;
    if (pos_filter.output() > AXIS_HALF_RANGE)
    {
      axis_pos = AXIS_HALF_RANGE;
      hardstop_dc = max(-HARDSTOP_DC, (AXIS_HALF_RANGE - pos_filter.output()) * (HARDSTOP_DC / HARDSTOP_FADE));
    }
    else if (pos_filter.output() < -AXIS_HALF_RANGE)
    {
      axis_pos = -AXIS_HALF_RANGE;
      hardstop_dc = min(HARDSTOP_DC, (-AXIS_HALF_RANGE - pos_filter.output()) * (HARDSTOP_DC / HARDSTOP_FADE));
    }
    else
    {
      axis_pos = round(pos_filter.output());
    }

    float feedback_dc = 0.0f;
    myeffectparams[0].springPosition = axis_pos;
    myeffectparams[0].damperVelocity = bound(pos_filter.rate(), -MAX_RATE, MAX_RATE);
    myeffectparams[0].inertiaAcceleration = bound(vel_filter.rate() * 0.1f, -32767, 32767);
    myeffectparams[0].frictionPositionChange = myeffectparams[0].damperVelocity;
    Joystick.setEffectParams(myeffectparams);
    Joystick.getForce(forces);
    Joystick.setXAxis(axis_pos);
    Joystick.sendState();
    digitalWrite(LED_PIN, forces[0] >= 255 || forces[0] <= -255);
    feedback_dc = forces[0] * (FEEDBACK_DC / 255);

    const float feed_forward_duty_cycle = pos_filter.rate() * (ICR / MAX_RATE);
    const float duty_cycle = bound(feed_forward_duty_cycle + hardstop_dc + feedback_dc, -ICR, ICR);
    float brake_duty_cycle = 0.0f;
    if ((duty_cycle > 0 && duty_cycle < feed_forward_duty_cycle) ||
        (duty_cycle < 0 && duty_cycle > feed_forward_duty_cycle))
    {
       // We're regen braking. We need to turn on the brake resistor.
       brake_duty_cycle = bound(BRAKE_MULTIPLIER * sqrtf(feed_forward_duty_cycle * duty_cycle - duty_cycle * duty_cycle), 0, ICR);
    }    
    digitalWrite(DIR_PIN, duty_cycle < 0);
    analogWrite16(PWM_PIN, duty_cycle >= 0 ? duty_cycle : -duty_cycle);
    analogWrite16(BRAKE_PIN, brake_duty_cycle);
  }
}

sgtnoodle avatar Jan 12 '22 04:01 sgtnoodle

I was experimenting on this in Project Cars 2. With all FFB functions disabled in my code, the game doesn't even start. With the original Joystick (without FFB) library, my code works just fine. The problem must be in that direction somewhere.

s-zenichev avatar Feb 06 '22 09:02 s-zenichev

I tested the lib in Assetto Corsa & Project-Cars 2, it works well. But in Horizon 4 it seems would slow down the fps in the game, the same probolem as you said.It needs some time to fix.😂

YukMingLaw avatar Feb 19 '22 13:02 YukMingLaw

Thanks for looking into this, i will be following the development of this issue with great interest

ThePixelArtist avatar Feb 21 '22 20:02 ThePixelArtist

hello,bug seems be found!I set Y axis enable variable as False,and it work normal.I guess the Horizon 4/5 not support the second force feedback Axis to cause this problem. I will update an new API to set the force feedback Axis enable or not.

YukMingLaw avatar Jul 14 '22 01:07 YukMingLaw

That's interesting. In my steering wheel project, I originally omitted the Y axis from the joystick. It worked in the games I tried, but none of the force feedback test applications worked with it. I enabled the Y axis but with a dummy position value, and the test applications started working.

I suppose you're talking about some other sort of axis enable, that isn't already part of the API?

On Wed, Jul 13, 2022, 6:02 PM York Law @.***> wrote:

hello,bug seems be found!I set Y axis enable variable as False,and it work normal.I guess the Horizon 4/5 not support the second force feedback Axis to cause this problem. I will update an new API to set the force feedback Axis enable or not.

— Reply to this email directly, view it on GitHub https://github.com/YukMingLaw/ArduinoJoystickWithFFBLibrary/issues/37#issuecomment-1183835432, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACNKBVIWA3U4U4MG67FHJNTVT5RLHANCNFSM5LPM7GZQ . You are receiving this because you commented.Message ID: @.***>

sgtnoodle avatar Oct 11 '22 09:10 sgtnoodle

I found the final problem, which has nothing to do with the Y-axis enable_setting. Mainly the axis value sending frequency and the data frequency of obtaining force feedback do not conform to the game's internal force feedback calculation system, I guess that the force feedback calculation system used in some games is a synchronization mechanism, each axis data update will recalculate the force feedback value, and then send it to the device, and finally update the screen, which leads to a decline in FPS. which can fix the problem as follow:

void loop(){
//do something
  interval = interval  + 1;
  if(interval % 50 == 0){ // update the X Axis value at regular intervals
    Joystick.setXAxis(value); //update X Axis value
    interval = 0;
  }
  
  effectparams[0].springMaxPosition = ENCODER_MAX_VALUE;
  effectparams[0].springPosition = value;
  effectparams[1].springMaxPosition = ENCODER_MAX_VALUE;
  effectparams[1].springPosition = 0;
  Joystick.setEffectParams(effectparams);
  Joystick.getForce(forces);
//do something
}

YukMingLaw avatar Oct 15 '22 17:10 YukMingLaw