Skip to content

Add FGAuxiliary setters for host-owned propagation - #1482

Closed
Zaretto wants to merge 1 commit into
JSBSim-Team:masterfrom
Zaretto:feature/aux-host-propagation-setters
Closed

Add FGAuxiliary setters for host-owned propagation#1482
Zaretto wants to merge 1 commit into
JSBSim-Team:masterfrom
Zaretto:feature/aux-host-propagation-setters

Conversation

@Zaretto

@Zaretto Zaretto commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Together with the per-model enable property (#1481), these five FGAuxiliary setters are the main JSBSim-core changes that permit running the engine inside an externally hosted simulation such as DCS World.

Adds to FGAuxiliary:

  • Setadot, Setbdot (alpha/beta rates)
  • SetNx, SetNy, SetNz (body-axis load factors)

When a host owns the state integration it injects the derived quantities Auxiliary would otherwise compute from the propagation it no longer runs. The host-owned domain is propagation together with ground reactions, tightly coupled through the 6DoF integration and externalised as one unit. These rates and load factors are among the few quantities Auxiliary cannot recompute once that integration is external, so the host supplies them.

Follows the state-propagation review @agodemar raised in #1390 and #1391.

@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 25.10%. Comparing base (0b99c70) to head (21c95aa).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1482   +/-   ##
=======================================
  Coverage   25.10%   25.10%           
=======================================
  Files         171      171           
  Lines       18843    18843           
=======================================
  Hits         4731     4731           
  Misses      14112    14112           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Adds Setadot, Setbdot, SetNx, SetNy and SetNz to FGAuxiliary so a host that owns the state integration can inject the alpha/beta rates and body-axis load factors that Auxiliary would otherwise derive from the propagation it is no longer running.

The host-owned domain is propagation together with ground reactions. The two are tightly coupled through the 6DoF integration and are externalised as one unit, so when a host takes them over these are among the few derived quantities Auxiliary cannot recompute and must be supplied.

Together with the per-model enable property (JSBSim-Team#1481), this is the main JSBSim-core change needed to host the engine inside an externally hosted simulation such as DCS World. The rest reuses existing mechanisms: atmosphere override, FGWinds, and the existing velocity setters. A large capability for a small, additive surface. It follows the state-propagation review that Agostino De Marco raised in JSBSim-Team#1390 and JSBSim-Team#1391.
@Zaretto
Zaretto force-pushed the feature/aux-host-propagation-setters branch from 89c914c to 21c95aa Compare June 23, 2026 12:32
@agodemar

Copy link
Copy Markdown
Contributor

Overall, it looks good to me, thanks @Zaretto for this solution.
@bcoconni and @seanmcleod70 any comments on this?

@seanmcleod70

Copy link
Copy Markdown
Contributor

Will take a look on the weekend at this PR and #1481 to refresh my memory of the details.

@seanmcleod70

Copy link
Copy Markdown
Contributor

@Zaretto how come there are so few new FGAuxiliary functions?

Looking at my comment - #1390 (comment) in the previous discussion I noted 12 new FGAuxiliary functions that you had added to your fork at the time but with this PR you've only added 5.

@bcoconni

bcoconni commented Jun 30, 2026

Copy link
Copy Markdown
Member

There again I agree with @seanmcleod70 and in addition to that, this looks to me like a quick and dirty implementation to solve the particular issues that the DCS interface is facing.

The problem is that in most cases these methods will be no-op's because the content passed to the setters will be overwritten by the method FGAuxiliary::Run, unless the FGAuxiliary model is disabled using the feature submitted by PR #1481. That does not look like a great API design to me.

My point here is not to reject the PR upfront but to tell that:

  1. This PR and PR Add a per-model execution-enable property #1481 are strongly interconnected. And they should not be designed and reviewed separately.
  2. We need to put much thoughts into these 2 PRs before proceeding. This implies suggesting and reviewing alternative designs to select the most reasonable one based on a discussion about their relative merits.

Also why are the setters not used to allow modifying their related properties ?

PropertyManager->Tie("accelerations/Nx", this, &FGAuxiliary::GetNx);
PropertyManager->Tie("accelerations/Ny", this, &FGAuxiliary::GetNy);
PropertyManager->Tie("accelerations/Nz", this, &FGAuxiliary::GetNz);

PropertyManager->Tie("aero/alphadot-deg_sec", this, inDegrees, &FGAuxiliary::Getadot);
PropertyManager->Tie("aero/betadot-deg_sec", this, inDegrees, &FGAuxiliary::Getbdot);

@Zaretto

Zaretto commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@seanmcleod70 With only propagate and ground reactions disabled, Auxiliary still runs, so the only things that
cannot be calculated are the five variables derived from the propagation the host owns.

@bcoconni I think making these five properties that are already bound read/write is a much better solution than adding methods, and one that will permit this all to be done from the XML.

This is not designed as a Q&D way to integrate DCS as I've already done that, as discussed on #1390. This is a real attempt to bring extra functionality into JSBSim that will have more widespread use and increase the flexibility of what JSBSim can be used for. I've already seen one real world case where JSBSim couldn't be used without patches

Merging #1481 into this is my preferred approach but I will take guidance.

@seanmcleod70

Copy link
Copy Markdown
Contributor

With only propagate and ground reactions disabled, Auxiliary still runs, so the only things that
cannot be calculated are the five variables derived from the propagation the host owns.

Yep, I relooked at the code in that context, i.e. FGAuxiliary::Run() still being called, and the 5 variables this PR enables to be set externally, but I'm a bit confused given that FGAuxiliary::Run() calculates adot and bdot.

adot = (vAeroUVW(eU)*in.vUVWdot(eW) - vAeroUVW(eW)*in.vUVWdot(eU))/mUW;
bdot = (in.vUVWdot(eV)*Vt - vAeroUVW(eV)*Vtdot)/(Vt*sqrt(mUW));

I must be missing something?

@bcoconni

bcoconni commented Jul 6, 2026

Copy link
Copy Markdown
Member

Yes I agree with @seanmcleod70, if FGPropagate is disabled then the PR needs to manually update the properties from FGPropagate that are no longer updated but are still fed to the other models? The code of FGAuxiliary needs not be modified? 🤔

I think making these five properties that are already bound read/write is a much better solution than adding methods, and one that will permit this all to be done from the XML.

Yes, I like this idea with one caveat: the properties are currently read-only (they only have a getter) so you will need to re-wire them on the fly to make them read/write as soon as the model is disabled.

@Zaretto

Zaretto commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Since I first had the idea of using JSBSim inside DCS it's been quite a journey, and the last few months have achieved real progress because now I've got acEFM working with zero changes to JSBSim. Credit for this goes to @seanmcleod70 and @bcoconni for the thorough review of my pull requests that has consistently guided what I've been doing into the right places in the codebase.

In the end all that was needed was simply to set the integrators in FGPropagate to eNone and ensuring the gear stays retracted; which makes #1481 not important.

@seanmcleod70

Copy link
Copy Markdown
Contributor

@Zaretto great to hear it's as simple as disabling the integrators in JSBSim.

Just trying to understand the comment about in.vUVWdot being stale?

    // Alpha/beta rates - Auxiliary::Run() zeros adot/bdot then recomputes
    // from in.vUVWdot (which is stale in DCS mode). We compute from
    // frame-to-frame differencing and apply AFTER Run() in update().
    if (init_body) {
        double factor = 1.0 / dT;
        pending_adot = (alpha_rads - last_alpha_rads) * factor;
        pending_bdot = (beta_rads - last_beta_rads) * factor;
    }
....
....
    // DCS-provided Vt for debug logging (Auxiliary will compute its own from vAeroUVW)
    double Vt_ms = Magnitude(vx - wind_vx, vy - wind_vy, vz - wind_vz);

@Zaretto

Zaretto commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Apologies - I didn't expect you to review that before I'd finished it. This has now gone and a general tidy up of the interface is completed; if you get a moment to have a quick look I'd appreciate your input.

Zaretto added a commit to Zaretto/acEFM that referenced this pull request Jul 11, 2026
Integration is suppressed by setting the Propagate integrators all to eNone at init. We then inject the state from set_current_state_body_axis which will no longer be overwritten by Propagate.

This removes the need for new setters (JSBSim-Team/jsbsim#1482) and the need to disable modules (JSBSim-Team/jsbsim#1481) and also . GroundReactions now runs but we keep it effectively disabled by never extending the gear and by having no contact points. There is still an argument for keeping the ability to disable modules but we will wait and see what the JSBSim-Team decides.

EarthPositionAngle is forced to zero every frame because the DCS World's world is static and does not rotate and not doing this would probably cause longitude to drift west.

In set_current_state_body_axis the attitude is now set before the body velocity. SetUVW converts body velocity to inertial using the transforms in force and then Propagate::Run's CalculateUVW inverts that using the transforms. Setting the attitude first makes both directions use the same frame.

Because this now looks like finished, validated code I have taken the leap to strip all the commented-out FlightGear interface code carried in JSBSim_interface since the port.
@seanmcleod70

Copy link
Copy Markdown
Contributor

No problem, I was just quite keen to refresh my memory of the integration of JSBSim as an external flight model for DCS, so went and took a quick look, and given this particular PR with regards to FGAuxiliary also looked out for this code.

I've taken a new look after your tidy up, in particular glancing through these 2 files.

https://github.com/Zaretto/acEFM/blob/master/flyt-EFM-dcsJSBSim/JSBSim_interface.cpp
https://github.com/Zaretto/acEFM/blob/master/flyt-EFM-dcsJSBSim/DCS_interface.cpp

Given your comment about simply needing to disable the integrators in JSBSim, i.e.

    // DCS owns the state, so set all four Propagate integrators to eNone which
    // disables integration and permits injection of the state injected in
    // set_current_state_body_axis
    fgSetDouble("/fdm/jsbsim/simulation/integrator/rate/rotational", 0);
    fgSetDouble("/fdm/jsbsim/simulation/integrator/rate/translational", 0);
    fgSetDouble("/fdm/jsbsim/simulation/integrator/position/rotational", 0);
    fgSetDouble("/fdm/jsbsim/simulation/integrator/position/translational", 0);

I guess my initial thoughts were that the breakdown between DCS and JSBSim was along the lines in the following diagram, with JSBSim's responsibilities in the grey block, and with DCS taking care of the blocks I've circled in pale blue.

image

However, looking at the code, it isn't the case that DCS simply takes $\dot{X}$ from JSBSim, integrates it and returns $X$.

Rather, you supply DCS with the total force and total moment (excluding gear) from JSBSim and then DCS uses that, with mass information etc. to run the 6-DOF dynamics, and integrates the result that you then feed back into JSBSim. In other words, the blocks I've highlighted in green are also DCS blocks, including the atmosphere.

void ed_fm_add_local_force(double &x, double &y, double &z, double &pos_x, double &pos_y, double &pos_z)
{
    FGJSBsim *model = get_model();
    x = model->fgGetDouble("/fdm/jsbsim/forces/fbx-total-lbs") * LBS_TO_N;
    y = -model->fgGetDouble("/fdm/jsbsim/forces/fbz-total-lbs") * LBS_TO_N;
    z = model->fgGetDouble("/fdm/jsbsim/forces/fby-total-lbs") * LBS_TO_N;

    pos_x = center_of_mass.x;
    pos_y = center_of_mass.y;
    pos_z = center_of_mass.z;
}
void ed_fm_add_local_moment(double &x, double &y, double &z)
{
    FGJSBsim *model = get_model();

    // jsb
    // x + back
    // y + right
    // z + up

    // dcs
    // x + forward
    // y + up
    // z + right

    x = model->fgGetDouble("/fdm/jsbsim/moments/l-total-lbsft") * LBSFT_TO_NM;
    y = -model->fgGetDouble("/fdm/jsbsim/moments/n-total-lbsft") * LBSFT_TO_NM;
    z = model->fgGetDouble("/fdm/jsbsim/moments/m-total-lbsft") * LBSFT_TO_NM;
}

You then feed $X$ back into JSBSim via these and a couple of other functions. Although DCS's alpha and beta are ignored.

void FGJSBsim::set_current_state_body_axis(
    double ax, double ay, double az,                      // linear acceleration component in body coordinate system
    double vx, double vy, double vz,                      // linear velocity component in body coordinate system
    double wind_vx, double wind_vy, double wind_vz,       // wind linear velocity component in body coordinate system
    double omegadotx, double omegadoty, double omegadotz, // angular accelearation components in body coordinate system
    double omegax, double omegay, double omegaz,          // angular velocity components in body coordinate system
    double yaw, double pitch, double roll,                // radians
    double alpha_rads,                                    // AoA radians
    double beta_rads,                                      //AoS radians
    double dT,
    double ro_kgm3
)
void FGJSBsim::set_altitude(double h_ft)
{
    Propagate->SetAltitudeASL(h_ft);
}

Maybe we should move this discussion to a Github JSBSim discussion regarding general questions and answers about using JSBSim as an external flight model for DCS so that it's easier for others to find as opposed to being buried within the comment section of this PR?

@agodemar

Copy link
Copy Markdown
Contributor

Maybe we should move this discussion to a Github JSBSim discussion regarding general questions and answers about using JSBSim as an external flight model for DCS so that it's easier for others to find as opposed to being buried within the comment section of this PR?

@seanmcleod70 agreed

@seanmcleod70

Copy link
Copy Markdown
Contributor

Okay I've created a new discussion item for this at - #1488

@bcoconni

Copy link
Copy Markdown
Member

So I guess this PR can now be closed?

@seanmcleod70

Copy link
Copy Markdown
Contributor

@Zaretto closing this PR, there is a discussion item at - #1488.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants