This short tutorial explains how to create new profile and how scripting engine works.

Creating new profile

For most of supported games there are already built-in profiles. However in case a custom profile is needed, one can start from cloning existing profile or start from scratch.

1. Open main program window and click on existing profile.
2. Click Clone

3. Enter name for new profile and click OK.

4. The Profile Editor will be opened.
5. For purpose of this exercise, remove all scripts except the one for Any platform.

5. Click Save to apply changes.
6. Click View – it will open a directory contains the script.

7. Finally open the script (*.js) in text editor (e.g. Notepad, Notepad++).

NOTE: ForceSeatPM monitors for changes in script file. It means that when the script file is modified in e.g Notepad, there is no need to reactive the profile. ForceSeatPM will automatically reload the script as long as the profile the script belongs to is still active.

Input and effects plug-ins

Before moving to script modification, here is explanation of Input and Effects plug-ins role in motion profiles.

Input plug-in

Input plug-in defines source of main telemetry data. Below is a list of plug-ins and their purposes. Please notice that this list can change in next version of the software.

  • FlighSimulator – dedicated for Microsoft Flight Simulator X
  • GPBikes – dedicated for PiBoSo GP-Bikes
  • IL2 – dedicated for IL2
  • Outsim – dedicated for games that uses Outsim protocol, for example: Live For Speed, GRID, GRID 2, Dirt, Dirt 2, Dirt 3, F1 2010, F1 2011, F1 2012
  • RFBaseGame – for games that uses the same plug-in API as rFactor 1/ 2 e.g.: rFactor, rFactor 2, Game Stock Car 2012.
    Please notice that there is different connector for rFactor 2 comparing to rFactor 1 but still both are supported by the same plug-in on ForceSeatPM side.
  • SimBinRace – dedicated for games from SimBin, e.g.: GTR2, Race 07 family, RaceRoom Racing Experience
  • XPlane – dedicated for X-Plane 10, both x86 and x64

Besides game specific plug-ins there are also more generic plugins:

  • DirectInput – it captures a steering wheel/joystick device, it can be used with any game that uses Microsoft DirectInput interface to interact with a game controller. Usually it is good to combine it with ForceFeedback as effect plug-in.
  • OpenMotionInterface – for programs and games that use Open Motion Interface API.
  • ForceSeatMI – for programs and games that use MotionSystem ForceSeatMI API which is a part of ForceSeat SDK.

Some plug-ins require a connector (a different type of plug-in, usually DLL library) to be installed in a game folder, other just need game reconfiguration.

In most cases all these tasks (connector installation and game reconfiguration) are done by ForceSeatPM semi-automatically – they appear as issues in Action Center and one just has to click Install or Configure.

However if for some reason ForceSeatPM is not able to find game installation folder, manual connector installation has to be performed via Games Integration.

Effects plug-in

Effects plug-in defines second source of data, usually effects data like bumps and hits. Currently there is only one plug-in which captures ForceFeedback data sent from a game to the game controller. This requires the game to use ForceFeedback protocol and send some useful information to the game controller, please notice that not all games do it.

From technical point of view, the plug-in transforms captured force feedback related information into single value called Force0. Additionally there is Force1 introduced for convenience – it is an absolute value of Force0.

Please notice Force0 and Force1 parameters can change in a very abrupt way. If they are not properly scaled, it is possible that the device will perform very rapid movements, which could ultimately damage the delicate components of the simulator or harm the user.

ForceFeedback plug-in requires specific system configuration. ForceSeatPM can find all installed controllers and create an Action Center issues for them so they can be configured with a single click. Please notice that capturing ForceFeedback changes registry and installs a monitor next to the game controller driver.

It is possible that the monitor will affect driver’s normal operation. In that case, it is necessary to disable monitor for specific game controller.

In order to enable or disable ForceFeedback monitor for selected game controller you should:

  1. Open profile that uses Forcefeedback as effects plug-in (this profile does not have to be active)
  2. Click Configure next to Effects plug-in
  3. Go to Shared section
  4. Check which game controller should be monitored
  5. Click Ok.
  6. UAC (User Account Control) will be displayed as changing registry requires higher privileges level

Motion cueing

Motion system moves according to the parameters specified in the motion profile. Input parameters come from input plug-in and/or effect plug-in and they can have different names depending on selected plug-ins. The final position of a platform is a result of combination and transformation of different values received from the game. This transformation can be performed by a mapping mechanism or by a script mechanism.

The first one calculates final position of the platform by applying list of defined transformations of input values. It is easy in use but it is limited to predefined algorithms and transformations.

The second one uses Javascript custom code that gets values from the game as input and outputs desired platform position.

Please notice that instead of direct actuator positions, it is recommended to use axes. In this approach e.g. left-right rotation can be transformed by firmware into motion of two actuators for 2-dof platform but also for six actuators movement for 6-dof platform. It makes the profile more independent to the platform configuration.

Following axes are used by ForceSeatPM and the platform firmware:

  • Left-Right rotation (Roll)
  • Rear-Front rotation (Pitch)
  • Horizontal Left-Right rotation (Yaw)
  • Down-Up movement (Heave)
  • Left-Right movement (Surge)
  • Rear-Front movement (Sway)

For both motion cueing mechanisms, it is very important to understand the relation between output values (axis values) and the actual platform motion:

  • If you want to stop the platform in a center position all parameters should be equal 0.
  • Maximum movement in each axis is represented by value of 32767 or -32767, for instance for left-right rotation, -32767 means maximum to the left, 32767 means maximum to the right

The system therefore can move to 65535 possible positions on each of the motion axis and it is important to scale parameters from the game to the range of (-32767, 32767). Additionally every platform has some latency, so it is also important to scale and filter all parameters to reduce visible effect of delay.

The whole trick is to figure out how to use limited actuators operating range and G-force to make a player thinks that he or she is affected by the same forces as in real world when e.g. he or she is driving a car.

Data mapping transformation

After selecting input and effects plug-in, it is time to define mapping between telemetry received from the game and platform movements. Let’s start with defining generic parameters:

  • Start Ramp – defines how fast an actuator should accelerate: rapid means that actuator will accelerate as fast as possible; very slow means that it can take even few seconds to achieve desired speed. Slow acceleration is recommended for flight simulators.
  • Stop Ramp – similar as above, but for breaking/stopping.
  • Maximum speed – maximum allowed actuators speed, the actuators will never move faster than this defined value. Please notice that setting this value to low can make the actuator not move at all.
  • Transformation type – defines if mapping or script code is used during calculation of platform position, for this example mapping is selected.

Next step is mapping definition. Click Add Mapping and first item will be added to a list. There are following fields that need configuration:

  • Source – name of the input value received from the game, usually it is good to use values related to acceleration in a vehicle coordinate system (e.g. Acceleration body X for rFactor)
  • Motion type – name of a platform axis
  • Algorithm– defines how to process telemetry value before sending it to the motion system:
    • 1:1 – no processing, pass unchanged value.
    • Delta Value – motion system receives the difference between a current value and a previous value.
    • Average of Last 2, 3 or 5 – motion system receives an average value of recent N values.
    • Offset – defines a contant value that is added to the parameter before it is proceeded.
    • Factor – value from the game is multiplied by the factor after applying algorithm and offset.
    • Range – the final value is reduced to defined range.

The final equation for single axis looks as follows:


You can use the same source a few times and you can also use the same axis a few times. In this case final value for axis is just a sum.

In theory data mapping looks simple, but the trick is to find the best parameters values and the best combination of different source signals. Usually it takes hours of experiments and diagnostic module can be useful here.

Typical scenario looks as follows:

  1. Create a basic profile for the game.
  2. Activate the profile and open diagnostic for input/effects plug-in. It can be done from Profile Editor (by clicking Diagnostic button) or from a main program window in profile details view.
  3. Start the game in a windowed mode (if it is possible), otherwise use second display.
  4. Play the game and observe platform movements and also values in diagnostic window.
  5. Adjust the profile.
  6. Repeat steps 4 and 5 until results are as expected.

Please notice that is it not necessary to reactivate the profile, it is enough to just click Save.

Script transformation

If the data mapping is not enough and additional processing has to be performed, the solution is script transformation mechanism. It uses Javascript to define a small program that transforms input data into platform’s axis: http://doc.qt.io/qt-5/ecmascript.html

When the built-in profile is cloned, it already has an script. Most of script for racing games uses MoSy_DefaultProcessor and usually it is enough to tune its parameters. For flight simulators usually combination of low pass filters is used. You can always check default scripts for reference.

Please notice that the script execution time is crucial. No delays, waits or long operations are allowed, otherwise it will introduce extra latency.

The script itself has to define a function called process(), all other functions and variables are optional.

The default script file contains a list of all available input fields (defined as global variables) and output axes that have to be set (also defined as global variables). It is up to a user to write a code that maps input fields into output fields. Usually it is good to use low pass and high pass filters to catch bump and hits and at the same time slightly smooth normal movements (left-right rotations).

For purpose of this tutorial, we will focus on racing games and adjusting parameters of “default processor”.

Signal filters for racing games

Parameters that configure motion platform moves are grouped into 6 categories. Each category is mapped to one axis.

For each of axis there is 7 parameters that configure low-pass and high-pass filters. Low-pass filter is used to get main trend from input signal and high-pass filter to get bumps, vibrations and other irregular and rapid signal changes.

Please check following script fragment for reference:

var rollLowPassFactor        = 45;
var rollHighPassFactor       = 10;
var rollOutputFactor         = 12;
var rollHighOutputFactor     = -7;
var rollMax                  =  90;
var rollHighPassFilterCutOff = 90;
var rollBumpMin              = 5;
 
var heaveLowPassFactor        = 25;
var heaveHighPassFactor       = 10;
var heaveOutputFactor         = 15;
var heaveHighOutputFactor     = -12;
var heaveMax                  = 25;
var heaveHighPassFilterCutOff = 30;
var heaveBumpMin              = 15;
 
// ...
 
function process() {
	var rollValue = -in_FieldAccGX * 10;
	var pitchValue = in_FieldAccGZ * 10;
	var heaveValue = in_FieldAccGY * 10;
	var yawValue = -in_FieldHeadingChange / 10;
	var surgeValue = in_FieldAccGZ * 10;
	var swayValue = -in_FieldAccGX * 10;
 
	MoSy_DefaultProcessor(rollValue, pitchValue, heaveValue, yawValue, surgeValue, swayValue);

The meaning of parameters is as follows:

  • …LowPassFactor – level of low-pass filter. Increasing this value makes the main trend smoother and reduces vibrations and bumps. Too big value can cause a lag between motion platform moves and moves in the game. Range: [1, ∞)
  • …HighPassFactor – level of high-pass filter. Low value causes output signal to change rapidly with high amplitude. Increasing this value reduces amplitude and frequency of the changes. This parameter is used to configure level of bumps. Range: [1, ∞)
  • …OutputFactor – it defines how much low-pass filter output value affects axis move. Range: [0, ∞)
  • …HighOutputFactor – it defines how much hight-pass filter output value affects axis move. Range: [0, ∞)
  • …Max – it limits maximum platform movement that comes from low-pass filter output value on axis. Range: [0, 127] – the value is multiplied by 256 in MySo_DefaultProcessor
  • …HighPassFilterCutOff – it limits maximum platform movement that comes from hight-pass filter output value on axis. Range: [0, 127] – the value is multiplied by 256 in MySo_DefaultProcessor
  • …BumpMin – it is used to eliminate small and frequent vibrations by high-pass filter and leave. Low value causes lot of vibrations in high-pass filter output signal. Range: [0, ∞)

Flight simulators – FSX and P3D

Both plug-ins use SimConnect interface. Each field in script is mapped to SimConnect variable. The mapping is as follows:

  • in_FieldVelocityBodyX – “VELOCITY BODY X”
  • in_FieldVelocityBodyY – “VELOCITY BODY Y”
  • in_FieldVelocityBodyZ – “VELOCITY BODY Z”
  • in_FieldAccelerationBodyX – “ACCELERATION BODY X”
  • in_FieldAccelerationBodyY – “ACCELERATION BODY Y”
  • in_FieldAccelerationBodyZ – “ACCELERATION BODY Z”
  • in_FieldRotationVelocityBodyX – “ROTATION VELOCITY BODY X”
  • in_FieldRotationVelocityBodyY – “ROTATION VELOCITY BODY Y”
  • in_FieldRotationVelocityBodyZ – “ROTATION VELOCITY BODY Z”
  • in_FieldPlaneAltAboveGround – “PLANE ALT ABOVE GROUND”
  • in_FieldPlanePitchDegrees – “PLANE PITCH DEGREES”
  • in_FieldPlaneBankDegree – “PLANE BANK DEGREES”
  • in_FieldTurnCoordinatorBall – “TURN COORDINATOR BALL”
  • in_FieldGForce – “G FORCE”
  • in_FieldGear0Position – “GEAR POSITION:0”
  • in_FieldGear1Position – “GEAR POSITION:1”
  • in_FieldSimOnGround – “SIM ON GROUND”
  • in_FieldWheelRpm – “WHEEL RPM”
  • in_FieldPlaneHeadingDegreesTrue – “PLANE HEADING DEGREES TRUE”
  • in_FieldPlaneHeadingDegreesMagnetic – “PLANE HEADING DEGREES MAGNETIC”

Detailed description of SimConnect variables can be found on following pages:

Additionally the script calculates bank ratio and pitch ratio:

  • bankRatio = delta(in_FieldPlaneBankDegree) / delta(Time)/li>
  • pitchRatio = delta(in_FieldPlanePitchDegrees) / delta(Time)

A helper class is used for it – MoSy_ChangeRatioCalculator(interval, ratioFactor, prevSmoothValue):

  • interval (ms) – how often should value be updated;
  • ratioFactor – factor for the output value;
  • prevSmoothValue (0..1] – smoothness factor of original signal.

The script has also access to following fields:

  • in_Paused – 0 working, 1 paused
  • in_SystemTime – current system time in milliseconds – it is used to calculate e.g. time delta for bank ratio and pitch ratio.

Flight simulators – X-Plane

Each field in script is mapped to DataRef variable. The mapping is as follows:

  • in_FieldLatitude – “sim/flightmodel/position/lat_ref”
  • in_FieldPitch – “sim/flightmodel/position/theta”
  • in_FieldRoll – “sim/flightmodel/position/phi”
  • in_FieldTrueHeading – “sim/flightmodel/position/psi”
  • in_FieldMagneticHeading – “sim/flightmodel/position/magpsi”
  • in_FieldLocalAccelerationX – “sim/flightmodel/position/local_ax”
  • in_FieldLocalAccelerationY – “sim/flightmodel/position/local_ay”
  • in_FieldLocalAccelerationZ – “sim/flightmodel/position/local_az”
  • in_FieldAngleOfAttach – “sim/flightmodel/position/alpha”
  • in_FieldYaw – “sim/flightmodel/position/beta”
  • in_FieldFlyPitch – “sim/flightmodel/position/vpath”
  • in_FieldFlyHeading – “sim/flightmodel/position/hpath”
  • in_FieldGroundSpeed – “sim/flightmodel/position/groundspeed”
  • in_FieldAirSpir – “sim/flightmodel/position/true_airspeed”
  • in_FieldSlipDeg – “sim/cockpit2/gauges/indicators/slip_deg”
  • in_FieldTurnRateHeading – “sim/cockpit2/gauges/indicators/turn_rate_heading_deg_pilot”
  • in_FieldTurnRateRoll – “sim/flightmodel/misc/turnrate_roll”
  • in_FieldForceDownwardByAllEngines – “sim/flightmodel/forces/fnrml_prop”
  • in_FieldForceSidewaysByAllEngines – “sim/flightmodel/forces/fside_prop”
  • in_FieldForceForwardByAllEngines – “sim/flightmodel/forces/faxil_prop”
  • in_FieldAeroForceDownward – “sim/flightmodel/forces/fnrml_aero”
  • in_FieldAeroForceSideways – “sim/flightmodel/forces/fside_aero”
  • in_FieldAeroForceForward – “sim/flightmodel/forces/faxil_aero”
  • in_FieldGearForceDownward – “sim/flightmodel/forces/fnrml_gear”
  • in_FieldGearForceSideways – “sim/flightmodel/forces/fside_gear”
  • in_FieldGearForceFordward – “sim/flightmodel/forces/faxil_gear”
  • in_FieldTotalWeight – “sim/flightmodel/weight/m_total”
  • in_FieldGForceDownward – “sim/flightmodel/forces/g_nrml”
  • in_FieldGForceForward – “sim/flightmodel/forces/g_axil”
  • in_FieldGForceSideways – “sim/flightmodel/forces/g_side”

Detailed description of variables can be found on following pages:

The script has also access to following fields:

  • in_Paused – 0 working, 1 paused
  • in_SystemTime – current system time in milliseconds – it is used to calculate e.g. time delta for bank ratio and pitch ratio.

Predefined functions in scripts

Beside standard Javascript functions, following predefined functions are also available in scripts:

  • MoSy_CutBump(value, threshold) – it cuts signal if it does not exceed specified minimum value.
    • value – source signal
    • threshold – required level of signal
    • return – if value > threshold then value – threshold else 0
    • example – rollSignal = MoSy_CutBump(rollSignal, 1000);
  • MoSy_LowPass(filteredValue, currentValue, maxValue, lowPassFactor) – it applies simple and fast low pass filter.
    • filteredValue – value accumulator from previous calls
    • currentValue – value received from the SIM
    • maxValue – bounds for output value (-maxValue, return, maxValue)
    • lowPassFactor – bigger value means slower output value changes
    • return – new filtered value
    • example – filteredRoll = MoSy_LowPass(filteredRoll, rollFromTheSim, 32000, 10);
  • MoSy_Bump(avgValue, currentValue, factor, threshold, maxValue) – it extracts bump value signal from source signal. It can be used to redirect bump to different output or filter them separately. This function calls MoSy_CutBumpinternally.
    • avgValue – average signal, e.g. result of low pass filtering
    • currentValue – value received from the SIM
    • factor – bump gain
    • threshold – required level of signal
    • maxValue – bounds for output value (-maxValue, return, maxValue)
    • return – extracted and filtered bump singal
    • example – roolBumps = MoSy_Bump(avgRoll, rollFromTheSim, 20, 1000, 32000);
  • MoSy_DefaultProcessor(rollValue, pitchValue, heaveValue, yawValue, surgeValue, swayValue) – advanced telemetry processor that applies low pass filters and bumps extracing on telemetry signal received from the SIM. Beside input parameters it uses static global configuration parameters and quick tunes values for preferences adjustments.
    • rollValue – roll signal from the SIM
    • pitchValue – pitch signal from the SIM
    • heaveValue – heavesignal from the SIM
    • yawValue – yaw signal from the SIM
    • surgeValue – surge signal from the SIM
    • swayValue – sway signal from the SIM
    • return – none

    Required global static configuration parameters (explained in section Signal filtering for racing games):

    • rollLowPassFactor, rollHighPassFactor, rollOutputFactor, rollHighOutputFactor, rollMax, rollHighPassFilterCutOff, rollBumpMin
    • pitchLowPassFactor, pitchHighPassFactor, pitchOutputFactor, pitchHighOutputFactor, pitchMax, pitchHighPassFilterCutOff, pitchBumpMin
    • heaveLowPassFactor, heaveHighPassFactor, heaveOutputFactor, heaveHighOutputFactor, heaveMax, heaveHighPassFilterCutOff, heaveBumpMin
    • yawLowPassFactor, yawHighPassFactor, yawOutputFactor, yawHighOutputFactor, yawMax, yawHighPassFilterCutOff, yawBumpMin
    • surgeLowPassFactor, surgeHighPassFactor, surgeOutputFactor, surgeHighOutputFactor, surgeMax, surgeHighPassFilterCutOff, surgeBumpMin
    • swayLowPassFactor, swayHighPassFactor, swayOutputFactor, swayHighOutputFactor, swayMax, swayHighPassFilterCutOff, swayBumpMin

    Required quick tunes parameters defined in Profile Editor (if user is allowed to adjust them) or defined as global variables (if user is not allowed to adjust them):

    • Overall Intensity (as quick tune in Profile Editor) or tune_Overall_Intensity (global variable)
    • Bumps Intensity (as quick tune in Profile Editor) or tune_Bumps_Intensity (global variable)
    • Roll Intensity (as quick tune in Profile Editor) or tune_Roll_Intensity (global variable)
    • Pitch Intensity (as quick tune in Profile Editor) or tune_Pitch_Intensity (global variable)
    • Heave Intensity (as quick tune in Profile Editor) or tune_Heave_Intensity (global variable)
    • Yaw Intensity (as quick tune in Profile Editor) or tune_Yaw_Intensity (global variable)
    • Surge Intensity (as quick tune in Profile Editor) or tune_Surge_Intensity (global variable)
    • Sway Intensity (as quick tune in Profile Editor) or tune_Sway_Intensity (global variable)
  • MoSy_DefaultProcessor2(rollValue, pitchValue, heaveValue, yawValue, surgeRotValue, surgeMovValue, swayRotValue, swayMovValue) – advanced telemetry processor that applies low pass filters and bumps extracting on telemetry signal received from the SIM. Beside input parameters it uses static global configuration parameters and quick tunes values for preferences adjustments.
    In contrast to MoSy_DefaultProcessor it allows to specify two signal sources for roll and pitch. It means that it is possible to e.g. roll the top frame as combination of vehicle roll and lateral acceleration in specified proportions.
  • rollValue – roll signal from the SIM
  • pitchValue – pitch signal from the SIM
  • heaveValue – heave signal from the SIM
  • yawValue – yaw signal from the SIM
  • surgeRotValue – surge signal from the SIM for top frame rotation (pitch)
  • surgeMovValue – surge signal from the SIM for top frame movement (surge)
  • swayRotValue – sway signal from the SIM for top frame rotation (roll)
  • swayMovValue – sway signal from the SIM for top frame movement (sway)
  • return – none

Required global static configuration parameters (explained in section Signal filtering for racing games):

  • rollLowPassFactor, rollHighPassFactor, rollOutputFactor, rollHighOutputFactor, rollMax, rollHighPassFilterCutOff, rollBumpMin
  • pitchLowPassFactor, pitchHighPassFactor, pitchOutputFactor, pitchHighOutputFactor, pitchMax, pitchHighPassFilterCutOff, pitchBumpMin
  • heaveLowPassFactor, heaveHighPassFactor, heaveOutputFactor, heaveHighOutputFactor, heaveMax, heaveHighPassFilterCutOff, heaveBumpMin
  • yawLowPassFactor, yawHighPassFactor, yawOutputFactor, yawHighOutputFactor, yawMax, yawHighPassFilterCutOff, yawBumpMin
  • surgeRotLowPassFactor, surgeRotHighPassFactor, surgeRotOutputFactor, surgeRotHighOutputFactor, surgeRotMax, surgeRotHighPassFilterCutOff, surgeRotBumpMin
  • surgeMovLowPassFactor, surgeMovHighPassFactor, surgeMovOutputFactor, surgeMovHighOutputFactor, surgeMovMax, surgeMovHighPassFilterCutOff, surgeMovBumpMin
  • swayRotLowPassFactor, swayRotHighPassFactor, swayRotOutputFactor, swayRotHighOutputFactor, swayRotMax, swayRotHighPassFilterCutOff, swayRotBumpMin
  • swayMovLowPassFactor, swayMovHighPassFactor, swayMovOutputFactor, swayMovHighOutputFactor, swayMovMax, swayMovHighPassFilterCutOff, swayMovBumpMin

Required quick tunes parameters defined in Profile Editor (if user is allowed to adjust them) or defined as global variables (if user is not allowed to adjust them):

  • Overall Intensity (as quick tune in Profile Editor) or tune_Overall_Intensity (global variable)
  • Bumps Intensity (as quick tune in Profile Editor) or tune_Bumps_Intensity (global variable)
  • Roll Intensity (as quick tune in Profile Editor) or tune_Roll_Intensity (global variable)
  • Pitch Intensity (as quick tune in Profile Editor) or tune_Pitch_Intensity (global variable)
  • Heave Intensity (as quick tune in Profile Editor) or tune_Heave_Intensity (global variable)
  • Yaw Intensity (as quick tune in Profile Editor) or tune_Yaw_Intensity (global variable)
  • Surge Intensity (as quick tune in Profile Editor) or tune_Surge_Intensity (global variable)
  • Sway Intensity (as quick tune in Profile Editor) or tune_Sway_Intensity (global variable)