News:

Precision Simulator update 10.184 (15 September 2025) is now available.
Navburo update 13 (23 November 2022) is now available.
NG FMC and More is released.

Main Menu

PFC Throttle Quadrant

Started by Bluestar, Tue, 29 Jul 2025 20:25

Bluestar

Hardy,

My PFC Throttle Quadrant (PFCTQ) does not work correctly with PSX. The PFCTQ works correctly with P3d, MSFS 2024 and x-Plane 12.  The problem is two of the levers have the same assignment when connected to PSX.  Two of the usbs are labeled "PFC Throttle Quadrant Consol - slider"  (see line 38 and 39 in the USB tab).  There should only be one marked as "slider".  The other should be marked as "dial". See the PFC Throttle Quadrant Counsel properties image below.     

Grace and Peace,

Bode

Hardy Heinlin

We discussed this 3 years ago and unfortunately I still can't provide a solution as the problem sits in that 3rd party USB Java interface.

Here's the original thread:

https://aerowinx.com/board/index.php/topic,6774.msg73081.html#msg73081


Regards,

|-|ardy

macroflight

@Bluestar: you could try using frankenusb to handle the PFCTQ. Since it uses a different way to access the USB devices (pygame, which in turn uses SDL) it might work better.

A quick test would be to download the latest binary package and run show_usb.exe. Then move your PFCTQ controls. If they show up in the show_usb.exe window (and don't have the same names) you should be able to use frankenusb.

You can still keep using native PSX USB for your other peripherals.

Bluestar

Quote from: macroflight on Wed, 30 Jul 2025 08:50@Bluestar: you could try using frankenusb to handle the PFCTQ. Since it uses a different way to access the USB devices (pygame, which in turn uses SDL) it might work better.

A quick test would be to download the latest binary package and run show_usb.exe. Then move your PFCTQ controls. If they show up in the show_usb.exe window (and don't have the same names) you should be able to use frankenusb.

You can still keep using native PSX USB for your other peripherals.

I will give it a try.

Grace and Peace
Grace and Peace,

Bode

Bluestar

Quote from: macroflight on Wed, 30 Jul 2025 08:50@Bluestar: you could try using frankenusb to handle the PFCTQ. Since it uses a different way to access the USB devices (pygame, which in turn uses SDL) it might work better.

A quick test would be to download the latest binary package and run show_usb.exe. Then move your PFCTQ controls. If they show up in the show_usb.exe window (and don't have the same names) you should be able to use frankenusb.

You can still keep using native PSX USB for your other peripherals.

I gave show_usb.exe a try and each of my six axes are showing.  Now how do I get these axes to work in frankenusb?
Grace and Peace,

Bode

voipmeister

Quote from: Bluestar on Mon, 18 Aug 2025 19:49I gave show_usb.exe a try and each of my six axes are showing.  Now how do I get these axes to work in frankenusb?
Have a look at the config examples in the repository, they should help you to get started. I would start with the axes and build out from there (buttons etc.). My Honeycomb Bravo throttle quadrant config is in the repository.

Please note that some events (like setting the trim) require a button 'down' as well as a button 'up' event. E.g. for trim the 'down' event should be either -1 or 1 and the 'up' event should be 0 to prevent the trim from running out of control.
Seb

macroflight

Quote from: Bluestar on Mon, 18 Aug 2025 19:49I gave show_usb.exe a try and each of my six axes are showing.  Now how do I get these axes to work in frankenusb?

You need to create a config file that tells frankenusb what you want the various axes and buttons to do in PSX. There's no pretty GUI, you edit a text file and map axes and buttons to PSX network commands.

I can help you get started on a config file, but it would help if I knew a little more about what you want your hardware to do.

Is this your hardware?


What do you want the six levers to do in PSX? Throttle 1-4? What about the other two levers? Any thoughts on how you want reverse to work?

What axis number does show_usb report when you move the leftmost lever? What value is reported when the lever is at the lower stop ("idle")? What value is reported at the forward stop ("full power")?

What is the USB device name that show_usb reports? (probably PFC something)

Do you want assistance in setting up e.g the landing gear lever, or is that already working?

Feel free to contact me in Discord chat (mk#3830).

Bluestar

Macro,

I have this control panel, but use the "Jet Throttle Quadrants / Two Engine Jet Enhanced Spoiler/Throttle/Reverser/Flap (GA Button)".  I use the GA Button as the A/T disconnect button.

Using show_usb the axis name is "PFC Throttle Quadrant Console".  The axis numbers are 1-6.  The gear lever is Button 0 UP, Button 1 DOWN.  The A/T disconnect is Button 4 UP, Button 4 DOWN.

Lever 1 = Speed Brakes, Lever 2 = Throttles All, Lever 3 = Reversers All, Lever 4 = Off, Lever 5 = Off,

Lever 6 = Flaps, Button 1 =Gear Cycle, Button 4 = A/T disconnect.

It is my hope to be able to change Lever 2 to Engine 1 and 2, Lever 3 Reversers 1 and 2, Lever 4 to Reversers 3 and 4, Lever 5 to Engines 3 and 4.

The axes range run from -.96 to .97. 

Let me know what other information you need. 
 
Grace and Peace,

Bode

macroflight

Quote from: Bluestar on Mon, 25 Aug 2025 15:39Let me know what other information you need.

I think that's enough information.

You are the first one who wants to use frankenusb with a separate USB axis for reverse thrust. So I will need to make a small code change to handle this.

Today frankenusb can handle throttles that are a single USB axis where we use an USB button to toggle between "normal mode" (where the USB axis controls one or more engines from idle thrust to full power) and "reverse mode" (where the same USB axis controls the same engines from idle reverse to full reverse).

To do what you want, I will need to add another throttle type to frankenusb that will work something like this:

- One USB axis controls one or more engines (two in your case) from forward idle to full power.
- Another USB axis will (IF the first axis is at idle power) control the same engines from reverse idle to full reverse)

So on landing you would pull Lever 2+5 back, giving you forward idle, and then push Lever3+4 slightly forward to get idle reverse, and even further forward for full reverse.

Another option would be to use four levers (2-5) for forward thrust, and use a USB button (on the PFC TQ or some other USB device) to toggle between normal mode and reverse mode. If that is what you want, no changes to frankenusb are needed, just a config file.

In this case, on landing you would pull all four levers back to get forward idle, then click a button that then gives you idle reverse, then push all four levers forward for full reverse. To stow the reversers and return to forward idle, pull the levers back and click the button.

I am willing to make the code change if you want the first option (might take a week or so to find the time), or make a config file for the second option. Just let me know what you prefer.

Bluestar

Macro,

I prefer option 1 since that is very close to what I am using. 

I'm in no hurry.  Just let me know what I need to do. 

Thanks,
Grace and Peace,

Bode

macroflight

Bluestar,

I have added new new axis types to frankenusb that should work more or less like the built-in Throttle and Reverse types in the native PSX USB (e.g you cannot use the reverse lever until the throttle has been closed).

You can download the new version of frankenusb from https://drive.google.com/drive/folders/1chA2V8kMiNvkhXVAZMbmtNrabXu3a1xO

In the ZIP is also a config file that you can use as a starting point (frankenusb-bluestar.conf).

If you rename it to frankenusb.conf, frankenusb.exe should find it automatically if you just double-click the exe.

But I recommend that you at least initially run frankenusb.exe from a terminal window of some kind (powershell or a good old cmd.exe), since that will let you see any fatal error messages (and you will get those e.g if you edit the config file and make an error).

The config file includes everything you described in your post (gear lever, A/P disconnect, speedbrake, flaps, throttles), i.e hopefully enough to not use the PSX USB stuff at all for the PFC TQ. If you only want to use frankenusb for throttle+reverse, you can just remove the other parts of the config file.

Bluestar

Thanks Macroflight, I will give it a try and let you know.   :)
Grace and Peace,

Bode

Bluestar

Macro,

The spoilers and flaps are now working.  I'm making slow progress on the throttles and reversers. 

I'm starting to understand the logic, just need a little more patience. ROFL.
Grace and Peace,

Bode

macroflight

Quote from: Bluestar on Thu, 28 Aug 2025 21:45The spoilers and flaps are now working.  I'm making slow progress on the throttles and reversers. 
Good news. :)

Let me know if you get stuck. Since I don't have a PFC TQ, I had to guess a little, so it's possible that the config file is not correct or even that the code has problems with your hardware (I used a Thrustmaster Airbus throttle for development with one lever for throttle and one for reverse).

Bluestar

Matts,

This is where I am.  All seems to work, just need to add a null zone for Reversers and Throttles when parked. I'm not sure what some of the numbers are, just used your example.

# -*- mode: Python;-*-
# pylint: disable=invalid-name,missing-module-docstring

CONFIG_MISC = {
    'THROTTLE_SYNC_SOUND': "C:/Aerowinx/Audio/Basics/cab1.wav"
}

CONFIG = {
    'PFC Throttle Quadrant Console': {
        'button down': {
            # Gear lever UP
            1: {
                'button type': 'SET',
                'psx variable': 'GearLever',
                'value': 1,
            },
            # Gear lever DOWN
            2: {
                'button type': 'SET',
                'psx variable': 'GearLever',
                'value': 3,
            },
            4: {
                # A/T disconnect
                'button type': 'SET',
                'psx variable': 'ThrustDisc',
        'value': 3,
            },
        },
        # 0 and 1.
        'button up': {
            # Gear lever neutral
            0: {
                'button type': 'SET',
                'psx variable': 'GearLever',
                'value': 2,
            },
            # Gear lever neutral
            1: {
                'button type': 'SET',
                'psx variable': 'GearLever',
                'value': 3,
            },
        },
    'axis motion': {
            1: {
                # Speedbrake
                'axis type': 'SPEEDBRAKE',
                'psx variable': 'SpdBrkLever',
                'axis swap': True,
        # When the axis value is less than this, the speedbrake is stowed
                'limit stowed': 0.15,
                # Else when the axis value is less than this, the speedbrake is armed
                'limit armed': 0.16,
                # Else when the axis value is greater than this, the speedbrake is full (ground)
                'limit flight upper': 0.90,
                # Else the speedbrake is in the flight range
            },
            2: {
                # Lever 2 controls Engine 1 and 2
                'axis type': 'AXIS_PSX_THROTTLE',
                'psx variable': 'Tla',  # required, and must be Tla
                'axis swap': False,
                'axis min': -0.99,
                'axis max': 0.99,
                'psx idle': 0,
                'psx full': 5000,
                'engine indexes': [0, 1],
            },
            3: {
                # Lever 3 controls Engine 1 and 2
                'axis type': 'AXIS_PSX_REVERSE',
                'psx variable': 'Tla',  # required, and must be Tla
                'axis swap': True,               
                'axis min': -0.99,
                'axis max': 0.99,
                'psx reverse idle': -3000,
                'psx reverse full': -8925,
                'engine indexes': [0, 1],
            },
            4: {
                # Lever 4 controls Engine 3 and 4
                'axis type': 'AXIS_PSX_REVERSE',
                'psx variable': 'Tla',  # required, and must be Tla
                'axis swap': True,
                'axis min': -0.99,
                'axis max': 0.99,
                'psx reverse idle': -3000,
                'psx reverse full': -8925,
                'engine indexes': [2, 3],
            },
            5: {
                # Lever 5 controls Engine 3 and 4
                'axis type': 'AXIS_PSX_THROTTLE',
                'psx variable': 'Tla',  # required, and must be Tla
                'axis swap': False,
                'axis min': -0.70,
                'axis max': 0.99,
                'psx idle': 0,
                'psx full': 5000,
                'engine indexes': [2, 3],
            },
            6: {
                'axis type': 'AXIS_SET',
                'psx variable': 'FlapLever',
                'axis swap': True,
                'zones': [
                    (0.900, 1.000, 0),
                    (0.615, 0.899, 1),
                    (0.314, 0.614, 2),
                    (-0.100, 0.313, 3),
                    (-0.512, -0.101, 4),
                    (-0.827, -0.513, 5),
                    (-1.001, -0.828, 6),
                ],
            },
        },
    },
}
Grace and Peace,

Bode

macroflight

I did not test this, but the code looks as if you should be able to use "static zones" (fancy names for null zone) for this axis type.

'static zones' is a list of tuples. Each tuple contains three numbers: the zone's minimum and maximum axis values, and the value that will be used as long as the axis is in that zone.

Example with a 5% null zone at the -1 end of the axis travel:

'static zones': [(-1.10, -0.95, -1.00)]
Example with a 5% null zone at the +1 end of the axis travel:

'static zones': [(0.95, 1.10, 1.00)]

Example with two zones - a 2% dead zone at each end of the axis travel:

'static zones': [(-1.1, -0.98, -1.0), (0.98, 1.1, 1.0)]

So you should try inserting a 'static zones' line into the axis definition where you want it, e.g

            2: {
                # Lever 2 controls Engine 1 and 2
                'axis type': 'AXIS_PSX_THROTTLE',
                'psx variable': 'Tla',  # required, and must be Tla
                'axis swap': False,
                'axis min': -0.99,
                'axis max': 0.99,
                'psx idle': 0,
                'psx full': 5000,
                'engine indexes': [0, 1],
                'static zones': [(-1.1, -0.95, -1.0)],
            },

Hardy Heinlin

Quote from: macroflight on Mon,  1 Sep 2025 13:19the value that will be used as long as the axis is in that zone.

Just curious: When the signal is exceeding the static zone, say, over the limit of 300, does your software output jump from 0 to 300 at that point, then 301, 302 etc. – or does it continue from the static reference value, e.g. 0, then 1, 2, 3 etc. at a factor that will exactly join the max value (e.g. 1000) when the axis hits the mechanical end?

In PSX it's a no-jump transition. E.g. if max is 1000 and the neutral zone is 0 to 500, it will continue from input 500 with output 0 at factor 2:

in : out
498: 0
499: 0
500: 0
501: 2
502: 4
...
998: 996
999: 998
1000:1000


macroflight

The static zone (I wrote that code a long time ago to the memory is a bit hazy) seems to simply replace the USB value with the fixed value for that zone. So when you move the lever out of the static zone, the PSX lever will jump a little.

    for zone in axis_config['static zones']:
         if zone[1] >= axis_position >= zone[0]:
              # in static zone
              axis_position = zone[2]

I probably wrote that code to handle axes that had a little noise at the endpoints, and in that case the PSX lever jump will not be noticeable. I guess I never imagined someone would use a 50% null zone. :)

But there is another thing that does something similar (and I see that Bluestar is using it): "axis min" and "axis max". Those can be used if you have an axis that doesn't go all the way out to -1.0 or +1.0.

E.g I have a physical stop on my throttle at around 81% of maximum to prevent the HOTAS buttons from banging into my desk, so I use "axis max": 0.62 on that axis. Then my PSX throttle is at idle when the USB axis is at -1.0, and increases linearly to full by the time the USB throttle hits the physical stop at 0.62.

The whole config system in frankenusb is very ad-hoc and grew as I added features. If I ever make a large re-write I'll try to improve it.

Bluestar

Quote from: Hardy Heinlin on Wed, 30 Jul 2025 07:34We discussed this 3 years ago and unfortunately I still can't provide a solution as the problem sits in that 3rd party USB Java interface.

Here's the original thread:

https://aerowinx.com/board/index.php/topic,6774.msg73081.html#msg73081


Regards,

|-|ardy

Hardy,

Is the 3rd party USB Java interface internal to PSX?
Grace and Peace,

Bode

Bluestar

Macroflight,

Is it possible to have the THROTTLE_SYNC_SOUND and the GEAR Lever Control separate from the Throttle Axis Throttle/Reserve?  I would like to try running the Throttle Sync Sound and Gear Lever Control as a separate module. 
Grace and Peace,

Bode