These are my notes on setting up JSBSim. I’m using JSBSim version 1.2.3 and Windows 11, but I’ll probably update this for Linux later.
Source code
Download and unzip https://github.com/JSBSim-Team/jsbsim/archive/refs/tags/v1.2.3.zip so that there’s a C:\jsbsim-1.2.3 folder.
Prerequisites
- Windows 11
- Visual Studio 2022 with C++ support
- cmake v3
Build and install
Open a command prompt and run the following commands:
cd C:\jsbsim-1.2.3
mkdir build
cd build
cmake .. -DBUILD_SHARED_LIBS=ON -DUSE_SIMGEAR=OFF -DCMAKE_INSTALL_PREFIX=../install
cmake --build . --config Release
cmake --install . --config Release
Notes
If there are warnings about Cython and/or CxxTest, these can be ignored (unless you want to build the Python module or want to run the test suite). For my purposes, I’m just using the JSBSim API in C++ apps. I’m setting an environment variable JSBSIMDIR to C:\jsbsim-1.2.3\install and using it in my CMakeLists.txt file.
Example main.cpp using JSBSim
This mimics the JSBSim binary in a minimal way by allowing the selection and execution of a JSBSim XML script. But it gives me a starting point for running something basic in a realtime loop where I can query status of the simulated aircraft. Here, I’m just printing some basic information to the console.
#include <FGFDMExec.h>
#include <iostream>
#include <iomanip>
#include <chrono>
#include <thread>
#include <string>
const double RAD2DEG = 180.0 / M_PI;
const double DEG2RAD = M_PI / 180.0;
const double dtSim = 0.01; // 100Hz = 0.01s per step
const double publishInterval = 1.0; // 1Hz
using namespace std::chrono;
using std::cout, std::endl, std::cerr, std::setprecision, std::string,
std::this_thread::sleep_until;
static void printUsage(std::string appName)
{
cout
<< "Usage:\n"
<< " " << appName << "\n"
<< " --rootDir <rootDir>\n"
<< " --script <script>\n "
<< " [--airCraftPath <airCraftPath> --enginePath <enginePath>]\n\n"
<< "Example: "
<< " " << appName << "\n"
<< " --rootDir C:/jsbsim-1.2.3\n"
<< " --script scripts/f16_test.xml\n"
<< " --airCraftPath aircraft\n"
<< " --enginePath engine\n"
<< endl;
}
int main(int argc, char* argv[])
{
if (argc == 1)
{
printUsage(argv[0]);
return 0;
}
string rootDir, script, airCraftPath{ "aircraft" }, enginePath{"engine"};
for (int i = 1; i < argc - 1; ++i)
{
if (string(argv[i]) == "--help" || string(argv[i]) == "--help")
{
printUsage(argv[0]);
return 1;
}
if (string(argv[i]) == "--rootDir")
{
rootDir = argv[i + 1];
cout << "Setting rootDir to " << rootDir << endl;
}
if (string(argv[i]) == "--script")
{
script = argv[i + 1];
cout << "Setting script to " << script << endl;
}
if (string(argv[i]) == "--airCraftPath")
{
airCraftPath = argv[i + 1];
cout << "Setting airCraftPath to " << airCraftPath << endl;
}
if (string(argv[i]) == "--enginePath")
{
enginePath = argv[i + 1];
cout << "Setting enginePath to " << enginePath << endl;
}
}
if (rootDir == "" || script == "")
{
cerr << "rootDir or script missing" << endl;
printUsage(argv[0]);
return 1;
}
JSBSim::FGFDMExec fdm;
fdm.SetRootDir(SGPath(rootDir));
fdm.SetAircraftPath(SGPath(airCraftPath));
fdm.SetEnginePath(SGPath(enginePath));
// Load the simulation script (relative to rootDir)
if (!fdm.LoadScript(SGPath(script)))
{
cerr << "Failed to load script" << endl;
return 1;
}
fdm.RunIC(); // Initialize aircraft
fdm.Setdt(dtSim);
auto wallStartTime = steady_clock::now();
double simTime = 0.0;
double nextStatusUpdateTime = 0.0;
while (fdm.Run())
{
simTime += dtSim;
// Print status every second
if (simTime >= nextStatusUpdateTime)
{
double time_s = fdm.GetSimTime();
double lat_deg = fdm.GetPropertyValue("position/lat-gc-deg");
double lon_deg = fdm.GetPropertyValue("position/long-gc-deg");
double alt_ft = fdm.GetPropertyValue("position/h-sl-ft");
double heading_rad = fdm.GetPropertyValue("attitude/psi-rad");
double pitch_rad = fdm.GetPropertyValue("attitude/theta-rad");
double roll_rad = fdm.GetPropertyValue("attitude/phi-rad");
double speed_fps = fdm.GetPropertyValue("velocities/u-fps");
cout
<< "T: " << setprecision(0) << time_s << ", "
<< "P: [" << setprecision(3) << lat_deg << ", " << lon_deg << "] @ "
<< setprecision(0) << alt_ft << " ft, "
<< "H: " << heading_rad * RAD2DEG << " deg, "
<< "P: " << pitch_rad * RAD2DEG << " deg, "
<< "R: " << roll_rad * RAD2DEG << " deg, "
<< "V: " << speed_fps << " fps"
<< endl;
nextStatusUpdateTime += publishInterval;
}
// Sync to wall-clock time
sleep_until(wallStartTime + duration<double>(simTime));
}
return 0;
}
Example CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(JSBSimExample)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(JSBSIM_INSTALL_DIR "C:/jsbsim-1.2.3/install")
include_directories(${JSBSIM_INSTALL_DIR}/include/JSBSim)
link_directories(${JSBSIM_INSTALL_DIR}/lib)
add_executable(JSBSimExample main.cpp)
target_link_libraries(JSBSimExample jsbsim)
Additional aircraft models
To download flightgear aircraft models:
git clone https://git.code.sf.net/p/flightgear/fgdata flightgear-fgdata