Examples presented in this document and the plugin have been made in Unreal Engine 4.14, 4.15 and 4.18. They might not work correctly with different versions of the Unreal Engine.

Plugin integration

Please follow below steps in order to include ForceSeatMI plugin into your project.

  1. Create C++ Unreal Engine project
  2. Inside root directory of your project create Plugins directory
  3. Copy ForceSeatMI plugin folder into Plugins directory
  4. Launch Unreal Engine editor
  5. Add ForceSeatMI plugin dependency to your project inside YourProject.Build.cs
    PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ForceSeatMI" });
  6. UE 4.15+ users: ForceSeatMI_VehicleTelemetry requires PhysXVehicles so make sure that this module it is added to your project
  7. After everything is built and compiled you can start using ForceSeatMI in your application!
ForceSeatMI plugin uses DLL which is installed as part of the ForceSeatPM software. Make sure that you have ForceSeatPM installed on your computer.

Application: top table positioning

Examples:

  • TableLogPos_Unreal shows positioning in abstract(logical, percents) units
  • TablePhyPos_Unreal shows positioning in real world units (Inverse Kinematics)

For both examples, use built-in ForceSeatPM profile SDK – Positioning or SDK – Pos – Low FPS.

Positioning application requires usage of raw ForceSeatMI API. Typical operation routine consists of following steps:

  1. Create a pointer member variable inside your class which will point to an instance of IForceSeatMI_API:
    IForceSeatMI_API* m_api;
  2. Initialize it in class constructor:
    m_api(&IForceSeatMI::Get().GetAPI())
  3. When simulation starts call (e.g. in BeginPlay() method of your APawn implementation):
    m_api->BeginMotionControl();
  4. The SIM should send positioning data in constant intervals using one of the following functions:
    m_api->SendTopTablePosLog(...);
    m_api->SendTopTablePosPhy(...);
    m_api->SendTopTableMatrixPhy(...);
  5. At the end of simulation call:
    m_api->EndMotionControl();

Code

Below code comes from TableLogPos_Unreal example.

ATableLogPos_UnrealPawn::ATableLogPos_UnrealPawn()
  : CurrentDrawingHeave(0)
  , CurrentDrawingPitch(0)
  , CurrentDrawingRoll(0)
{
  // ... generated UE4 code removed for better clarity
 
  // ForceSeatMI - BEGIN
  memset(&PlatformPosition, 0, sizeof(PlatformPosition));
  PlatformPosition.structSize = sizeof(PlatformPosition);
 
  // The demo program is able to provide pause, position and speed limit
  PlatformPosition.maxSpeed = PLATFORM_MAX_SPEED;
  PlatformPosition.mask     = FSMI_POS_BIT_STATE | FSMI_POS_BIT_POSITION | FSMI_POS_BIT_MAX_SPEED;
  // ForceSeatMI - END
}
 
void ATableLogPos_UnrealPawn::Tick(float DeltaTime)
{
  Super::Tick(DeltaTime);
 
  // ... generated UE4 code removed for better clarity
 
  // ForceSeatMI - BEGIN
  SendCoordinatesToPlatform();
  // ForceSeatMI - END
}
 
void ATableLogPos_UnrealPawn::BeginPlay()
{
  Super::BeginPlay();
 
  // ForceSeatMI - BEGIN
  if (FSMI_True == IForceSeatMI::Get().GetAPI().BeginMotionControl())
  {
    SendCoordinatesToPlatform();
  }
  // ForceSeatMI - END
 
  // ... generated UE4 code removed for better clarity
}
 
void ATableLogPos_UnrealPawn::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
  Super::EndPlay(EndPlayReason);
 
  // ForceSeatMI - BEGIN
  IForceSeatMI::Get().GetAPI().EndMotionControl();
  // ForceSeatMI - END
}
 
void ATableLogPos_UnrealPawn::SendCoordinatesToPlatform()
{
  // ForceSeatMI - BEGIN
  PlatformPosition.state = FSMI_STATE_NO_PAUSE;
  PlatformPosition.roll = static_cast(FMath::Clamp(CurrentDrawingRoll / DRAWING_ROLL_MAX  * PLATFORM_POSITION_LOGIC_MAX, PLATFORM_POSITION_LOGIC_MIN, PLATFORM_POSITION_LOGIC_MAX));
  PlatformPosition.pitch = static_cast(FMath::Clamp(CurrentDrawingPitch / DRAWING_PITCH_MAX * PLATFORM_POSITION_LOGIC_MAX, PLATFORM_POSITION_LOGIC_MIN, PLATFORM_POSITION_LOGIC_MAX));
  PlatformPosition.heave = static_cast(FMath::Clamp(CurrentDrawingHeave / DRAWING_HEAVE_MAX * PLATFORM_POSITION_LOGIC_MAX, PLATFORM_POSITION_LOGIC_MIN, PLATFORM_POSITION_LOGIC_MAX));
 
  IForceSeatMI::Get().GetAPI().SendTopTablePosLog(&PlatformPosition);
  // ForceSeatMI - END
}

Application: vehicle simulation

Examples: Telemetry_Veh_Unreal (use built-in ForceSeatPM profile SDK – Vehicle Telemetry)

For vehicle simulation application IForceSeatMI_VehicleTelemetry helper interface can be used. IForceSeatMI_VehicleTelemetry requires
PhysXVehicles and extracts automatically all necessary data from APawn and UWheeledVehicleMovementComponent objects.
Typical operation routine consists of following steps:

  1. Create a pointer member variable inside your class which will point to an instance of IForceSeatMI_VehicleTelemetry:
    IForceSeatMI_VehicleTelemetry* m_veh;
  2. Initialize it in class constructor:
    m_veh(&IForceSeatMI::Get().GetVehicleTelemetry())
  3. When simulation starts call (e.g. in BeginPlay() method of your APawn implementation):
    m_veh->Begin();();
  4. The SIM should send telemetry data in constant intervals using following function:
    m_veh->Tick(...);
  5. At the end of simulation call:
    m_veh->End();

Code

Below code comes from Telemetry_Veh_Unreal example.

void ATelemetry_Veh_UnrealPawn::Tick(float Delta)
{
  Super::Tick(Delta);
 
  // ... generated UE4 code removed for better clarity
 
  // ForceSeatMI - BEGIN
  IForceSeatMI::Get().GetVehicleTelemetry().Tick(*this, *GetVehicleMovement(), Delta, false/* no pause */);
  // ForceSeatMI - END
}
 
void ATelemetry_Veh_UnrealPawn::BeginPlay()
{
  Super::BeginPlay();
 
  // ForceSeatMI - BEGIN
  IForceSeatMI::Get().GetVehicleTelemetry().Begin();
  // ForceSeatMI - END
}

Application: flight simulation

Examples: Telemetry_Fly_Unreal (use built-in ForceSeatPM profile SDK – Plane Telemetry)

For flight simulation, a raw IForceSeatMI_API or IForceSeatMI_PlaneTelemetry helper interface can be used. IForceSeatMI_PlaneTelemetry automatically extracts
all necessary data from APawn object and then calculates missing information like accelerations.
Typical operation routine consists of following steps:

  1. Create a pointer member variable inside your class which will point to an instance of IForceSeatMI_PlaneTelemetry:
    IForceSeatMI_PlaneTelemetry* m_fly;
  2. Initialize it in class constructor:
    m_fly(&IForceSeatMI::Get().GetPlaneTelemetry())
  3. When simulation starts call (e.g. in BeginPlay() method of your APawn implementation):
    m_fly->Begin();();
  4. The SIM should send telemetry data in constant intervals using following function:
    m_fly->Tick(...);
  5. At the end of simulation call:
    m_fly->End();

Code

Below code comes from Telemetry_Fly_Unreal example.

void ATelemetry_Fly_UnrealPawn::Tick(float DeltaSeconds)
{
  // ... generated UE4 code removed for better clarity
 
  / Call any parent class Tick implementation
  Super::Tick(DeltaSeconds);
 
  // ForceSeatMI - BEGIN
  IForceSeatMI::Get().GetPlaneTelemetry().Tick(*this, DeltaSeconds, false/* no pause */);
  // ForceSeatMI - END
}
 
void ATelemetry_Fly_UnrealPawn::BeginPlay()
{
  Super::BeginPlay();
 
  // ForceSeatMI - BEGIN
  IForceSeatMI::Get().GetPlaneTelemetry().Begin();
  // ForceSeatMI - END
}

Related articles

You might be interested in following articles. If you want download SDK or purchase it, please visit product page.