Jump to content
The simFlight Network Forums
Pete Dowson

Using a trim wheel axis to operate with trim INC and DEC instead

Recommended Posts

A trim wheel, such as that sold by Saitek, is very nice, but unless it is motorised so that when the autopilot is controlling trim the wheel can be automatically moved to its correct position, it poses difficulties unless you fly under manual control all of the time.

With the autopilot operating the trim for vertical flight control modes, the wheel's position will not often match the actual trim position in FS. This doesn't matter if you don't move it, as axes are not read until moved. But as soon as you move it, the actual setting for the wheel position is immediately applied, resulting in a sudden trim change.

FSUIPC does have an option to disconnect the trim axis when the autopilot is using it (see the DisconnTrimForAP option in the Advanced User's guide), but this doesn't get over the discrepancy in the position when the A/P is disconnected. Really the only satisfactory way of having a trim wheel operate through the trim axis control is to have it motorised so that is always goes to the currently set FS position when the A/P adjusts it, or when you load a new flight.

An alternative, which can work but which does spoil some of the advantages of having a realistic trim wheel, is to revert it to sending elevator trim up and trim down commands to FS, instead of using the value directly as the trim vale. This effectively makes it similar to the NumPad 1 and 7 keys, or the spring-loaded two way toggle switches or levers fitted to many commercial yokes.

The way to do this is to use a Lua plug in which converts the change in axis value to a trim Inc or Dec. Here's an example:


function checkvalue(val)
if prev ~= nil then
if val > prev then ipc.control(65615)
elseif val < prev then ipc.control(65607)
end
end
prev = val
end

event.param("checkvalue")
[/CODE]

Save this as, say, "trimwheel.lua", in the Modules folder and add this to your INI file:

[Auto]

1=Lua trimwheel

Run FS and assign your axis, in the normal FS controls assignment on the left, to "Luavalue trimwheel".

Regards

Pete

Share this post


Link to post
Share on other sites

This appears to be an ideal solution to using my Saitek Pro Trim Wheel, but I ran into some caveats.

1) At least with the Saitek trim wheel, I had to reverse the values in the Lua script, which is an easy fix.  I did:

function checkvalue(val)
   if prev ~= nil then
		  if val > prev then ipc.control(65607)
		  elseif val < prev then ipc.control(65615)
		  end
   end
   prev = val
end

event.param("checkvalue")

2) If I turn the trim wheel too quickly, I do not get the full range of movement in the sim trim indication.  When I move the trim wheel quickly from its' lowest to highest positions, on the sim it is only moved about half way through its' range of motion.  If I move it slowly, I can get the full range of motion.  I suspect the trim wheel is sending the nose up/nose down commands too quickly and some of the commands are being ignored.  Is there anyway to fix this?

 

3) The last issue is something that is a limitation with the Saitek Trim Wheel, and cannot be fixed FSUIPC, but I am mentioning it as it is unexpected.  The issue is that the trim wheel has limits to the values it can send nose up or down, but turning the wheel there is no indication you have reached full nose up or down, or where you are in the range.  That means, if trim wheel is physically at nose up (or down), before you start the simulator, then in the sim you cannot trim more nose up (or down).  In this case having a trim wheel that does not have physical limits would be ideal.  I wonder if the Saitek can be modified.  Internally it uses a optical rotary position sensor.  This can somewhat worked around by going into FSUIPC and seeing what the position of the trim wheel is at and setting it to roughly what sim trim position you want to start with.

I am using Prepar3d v4.1 and FSUIPC v5.121b

Jessica

Share this post


Link to post
Share on other sites

I adjusted Pete's script to solve all three of your issues:

  1. The script writes directly to offset 0x0BC0
  2. For larger movements of the wheel the script makes larger changes the offset.
  3. If the wheel is near the end of its range (upper or lower 1/16th) a warning popup will appear and suggest disconnecting and reconnecting the wheel (I have connected it to the USB hub of my Saitek yoke, so this is easily reachable)

Additionally I have configured the trim wheel to set AP vertical speed or pitch or attitude hold if the AP is enabled instead of acting as a trim wheel.

And for the times I use only a joystick instead of the full setup, I have assigned two joystick buttons to act as trim, with increasing speed if the buttons are hold for a longer time.

Maybe you can adjust it for your own needs:

-- Using a trim wheel axis to operate with trim INC and DEC instead
-- http://forum.simflight.com/topic/72492-using-a-trim-wheel-axis-to-operate-with-trim-inc-and-dec-instead/
--
-- [Auto]
-- 1=Lua trimwheel
-- assign your axis, in the normal FS controls assignment on the left, to "Luavalue trimwheel".

boundary = 16384-2048

joystick = "J" -- Saitek Aviator Stick
button_dn = 4  -- T1
button_up = 5  -- T2

function trimbutton(joynum, button, downup)
  factor = 20
  direction = (button == button_up) and -1 or 1
  trimwheel(factor*direction)
  ipc.sleep(100)
  while ipc.testbutton(joynum, button) do
    if factor < 200 then
      factor = factor+2
    end
    trimwheel(factor*direction)
    ipc.sleep(30)
  end
  trimwheel(0)
end

function trimwheel_trim(change)
  trim = ipc.readSW(0x0BC0) - change
  if trim < -16384 then
    trim = -16384
  elseif trim > 16383 then
    trim = 16383
  end
  ipc.writeSW(0x0BC0, trim)
end

function trimwheel_ap_vs(change)
  if ipc.readUW(0x07BC) == 0 then -- AP disabled
    trimwheel_trim(change)
  elseif change > 0 then
    ipc.control(65895) -- AP_VS_VAR_DEC
  elseif change < 0 then
    ipc.control(65894) -- AP_VS_VAR_INC
  end
end

function trimwheel_ap_pitch(change)
  if ipc.readUW(0x07BC) == 0 then -- AP disabled
    trimwheel_trim(change)
  elseif change > 0 then
    ipc.control(66584) -- AP_PITCH_REF_INC_DN
  elseif change < 0 then
    ipc.control(66583) -- AP_PITCH_REF_INC_UP
  end
end

function trimwheel_ap_pitch_atthold(change)
  if ipc.readUW(0x07BC) == 0 then -- AP disabled
    trimwheel_trim(change)
  elseif change > 0 then
    if ipc.readUW(0x07D0) > 0 then -- AP alt lock
      ipc.control(65804, 1) -- AP_ATT_HOLD_ON
    end
    ipc.control(66584) -- AP_PITCH_REF_INC_DN
  elseif change < 0 then
    if ipc.readUW(0x07D0) > 0 then -- AP alt lock
      ipc.control(65804, 1) -- AP_ATT_HOLD_ON
    end
    ipc.control(66583) -- AP_PITCH_REF_INC_UP
  end
end

function trimwheel_ap_pitch_althold(change)
  if ipc.readUW(0x07BC) == 0 then -- AP disabled
    trimwheel_trim(change)
  elseif change > 0 then
    if ipc.readUW(0x07D0) > 0 then -- AP alt lock
      ipc.control(65816, 1) -- AP_ALT_HOLD_OFF
    end
    ipc.control(66584) -- AP_PITCH_REF_INC_DN
  elseif change < 0 then
    if ipc.readUW(0x07D0) > 0 then -- AP alt lock
      ipc.control(65816, 1) -- AP_ALT_HOLD_OFF
    end
    ipc.control(66583) -- AP_PITCH_REF_INC_UP
  end
end

function trimwheel_c182(change)
  if ipc.readUW(0x07BC) == 0 then -- AP disabled
    trimwheel_trim(change)
  elseif change > 0 then
    ipc.writeLvar("kap140_dn_button", 1)
  elseif change < 0 then
    ipc.writeLvar("kap140_up_button", 1)
  else
    ipc.writeLvar("kap140_dn_button", 0)
    ipc.writeLvar("kap140_up_button", 0)
  end
end

function aircraftchange(eventtype)
  if ipc.readSTR(0x3D00, 14) == "C337 Skymaster" then
    trimwheel = trimwheel_ap_pitch_atthold
  elseif ipc.readSTR(0x3D00, 5) == "C182_" then
    trimwheel = trimwheel_c182
  elseif ipc.readSTR(0x3D00, 10) == "Cessna 441" then
    trimwheel = trimwheel_ap_vs
  elseif ipc.readSTR(0x3D00, 20) == "Boeing Stratocruiser" then
    trimwheel = trimwheel_ap_pitch_althold
  else
    trimwheel = trimwheel_trim
  end
end

aircraftchange(nil) -- initialize at least once

function checkvalue(val)
  if prev ~= nil and val ~= prev then -- axis moved
    if math.abs(val) > boundary then
      ipc.display(string.format(
        "Warning:\n\n" ..
        "Trim wheel value near boundary: %d\n" ..
        "Reconnect to restore full range.\n",
        val), 10)
    else
      ipc.display("")
    end
    trimwheel(val - prev)
  end
  prev = val
end

event.sim(AIRCRAFTCHANGE, "aircraftchange")
event.param("checkvalue")
event.button(joystick, button_dn, "trimbutton")
event.button(joystick, button_up, "trimbutton")

 

Share this post


Link to post
Share on other sites

Thank you so much!  This really works well!

I modified the script slightly, but this really is an idea solution.

 

Jessica

-- Using a trim wheel axis to operate with trim INC and DEC instead
-- http://forum.simflight.com/topic/72492-using-a-trim-wheel-axis-to-operate-with-trim-inc-and-dec-instead/
--
-- [Auto]
-- 1=Lua trimwheel
-- assign your axis, in the normal FS controls assignment on the left, to "Luavalue trimwheel".

boundary = 16384-2048

function trimwheel_trim(change)
  trim = ipc.readSW(0x0BC0) - change
  if trim < -16384 then
    trim = -16384
  elseif trim > 16383 then
    trim = 16383
  end
  ipc.writeSW(0x0BC0, trim)
end

function trimwheel_ap_vs(change)
  if ipc.readUW(0x07BC) == 0 then -- AP disabled
    trimwheel_trim(change)
  elseif change > 0 then
    ipc.control(65895) -- AP_VS_VAR_DEC
  elseif change < 0 then
    ipc.control(65894) -- AP_VS_VAR_INC
  end
end

function trimwheel_ap_pitch(change)
  if ipc.readUW(0x07BC) == 0 then -- AP disabled
    trimwheel_trim(change)
  elseif change > 0 then
    ipc.control(66584) -- AP_PITCH_REF_INC_DN
  elseif change < 0 then
    ipc.control(66583) -- AP_PITCH_REF_INC_UP
  end
end

function trimwheel_ap_pitch_atthold(change)
  if ipc.readUW(0x07BC) == 0 then -- AP disabled
    trimwheel_trim(change)
  elseif change > 0 then
    if ipc.readUW(0x07D0) > 0 then -- AP alt lock
      ipc.control(65804, 1) -- AP_ATT_HOLD_ON
    end
    ipc.control(66584) -- AP_PITCH_REF_INC_DN
  elseif change < 0 then
    if ipc.readUW(0x07D0) > 0 then -- AP alt lock
      ipc.control(65804, 1) -- AP_ATT_HOLD_ON
    end
    ipc.control(66583) -- AP_PITCH_REF_INC_UP
  end
end

function trimwheel_ap_pitch_althold(change)
  if ipc.readUW(0x07BC) == 0 then -- AP disabled
    trimwheel_trim(change)
  elseif change > 0 then
    if ipc.readUW(0x07D0) > 0 then -- AP alt lock
      ipc.control(65816, 1) -- AP_ALT_HOLD_OFF
    end
    ipc.control(66584) -- AP_PITCH_REF_INC_DN
  elseif change < 0 then
    if ipc.readUW(0x07D0) > 0 then -- AP alt lock
      ipc.control(65816, 1) -- AP_ALT_HOLD_OFF
    end
    ipc.control(66583) -- AP_PITCH_REF_INC_UP
  end
end

function trimwheel_c182(change)
  if ipc.readUW(0x07BC) == 0 then -- AP disabled
    trimwheel_trim(change)
  elseif change > 0 then
    ipc.writeLvar("kap140_dn_button", 1)
  elseif change < 0 then
    ipc.writeLvar("kap140_up_button", 1)
  else
    ipc.writeLvar("kap140_dn_button", 0)
    ipc.writeLvar("kap140_up_button", 0)
  end
end

function aircraftchange(eventtype)
  if ipc.readSTR(0x3D00, 5) == "C182_" then
    trimwheel = trimwheel_c182 
  elseif ipc.readSTR(0x3D00, 12) == "Carenado A36" then
    trimwheel = trimwheel_ap_vs
  else
    trimwheel = trimwheel_trim
  end
end

aircraftchange(nil) -- initialize at least once

function checkvalue(val)
  if prev ~= nil and val ~= prev then -- axis moved
    if math.abs(val) > boundary then
      ipc.display(string.format(
        "Warning:\n\n" ..
        "Trim wheel value near boundary: %d\n" ..
        "Reconnect to restore full range.\n",
        val), 10)
    else
      ipc.display("")
    end
    trimwheel(val - prev)
  end
  prev = val
end

event.sim(AIRCRAFTCHANGE, "aircraftchange")
event.param("checkvalue")

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


×