Skip to content

Commit

Permalink
Prevent time catch up in real time mode (#1213)
Browse files Browse the repository at this point in the history
  • Loading branch information
bcoconni authored Jan 3, 2025
1 parent 330a6e3 commit 5be7eab
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 45 deletions.
11 changes: 11 additions & 0 deletions .github/workflows/cpp-python-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,17 @@ jobs:
rm -f _jsbsim.cxx # Make sure that jsbsim.cxx is not stored in the source distribution
python -m build --sdist
echo "::endgroup::"
- name: Check reset for real time execution
if: matrix.os == 'macos-14'
run: |
start_time=$(date +%s)
./build/src/JSBSim scripts/c172_cruise_8K.xml --realtime --nice
end_time=$(date +%s)
elapsed_time=$((end_time - start_time))
if [ $elapsed_time -lt 90 ]; then
echo "Failed - Program finished in less than 90 seconds"
exit 1
fi
# On failure, upload logs
- name: On failure - Upload logs
Expand Down
25 changes: 7 additions & 18 deletions scripts/c172_cruise_8K.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<description>This run is for testing the C172 altitude hold autopilot and cruise performance</description>
<use aircraft="c172x" initialize="reset01"/>

<run start="0.0" end="50" dt="0.0083333">
<run start="0.0" end="40" dt="0.0083333">

<property value="0" persistent="true"> simulation/run_id </property>

<event name="Set Temperature">
Expand All @@ -26,17 +26,17 @@
</set>
<set name="ap/altitude_setpoint" value="4000.0"/>
</event>

<event name="Start engine">
<condition>
simulation/sim-time-sec ge 0.01
</condition>
<set name="fcs/throttle-cmd-norm" action="FG_RAMP" value="0.50" tc="0.05"/>
<set name="fcs/mixture-cmd-norm" action="FG_RAMP" value="1.0" tc="0.05"/>
<set name="fcs/mixture-cmd-norm" action="FG_RAMP" value="1.0" tc="0.05"/>
<set name="propulsion/magneto_cmd" value="3"/>
<set name="propulsion/starter_cmd" value="1"/>
<notify/>
</event>
</event>

<event name="Trim">
<condition>
Expand Down Expand Up @@ -102,8 +102,8 @@

<event name="Reset">
<condition logic="AND">
simulation/sim-time-sec >= 30.0
simulation/terminate != 1
simulation/sim-time-sec >= 25.0
simulation/run_id lt 2
</condition>
<set name="ap/heading_setpoint" value="0"/>
<!-- <set name="ap/altitude_setpoint" value="0"/> -->
Expand All @@ -115,16 +115,5 @@
<property> simulation/run_id </property>
</notify>
</event>

<event name="Terminate on run ID">
<condition>
simulation/run_id ge 3
</condition>
<set name="simulation/terminate" value="1"/>
<notify>
<property caption="Terminate: "> simulation/terminate </property>
</notify>
</event>

</run>
</runscript>
71 changes: 51 additions & 20 deletions src/JSBSim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,44 @@ class XMLFile : public FGXMLFileRead {
}
};

/** The Timer class measures the elapsed real time and can be paused and resumed.
It inherits from SGPropertyChangeListener to restart the timer whenever a
property change is detected. */
class Timer : public SGPropertyChangeListener {
public:
Timer() : SGPropertyChangeListener(), isPaused(false) { start(); }
void start(void) { initial_seconds = getcurrentseconds(); }

/// Restart the timer when the listened property is modified.
void valueChanged(SGPropertyNode* prop) override {
start();
if (isPaused) pause_start_seconds = initial_seconds;
}
/// Get the elapsed real time in seconds since the timer was started.
double getElapsedTime(void) { return getcurrentseconds() - initial_seconds; }

/** Pause the timer if the `paused` parameter is true and resume it if the
`paused` parameter is false. */
void pause(bool paused) {
if (paused) {
if (!isPaused) {
isPaused = true;
pause_start_seconds = getcurrentseconds();
}
} else {
if (isPaused) {
isPaused = false;
double pause_duration = getcurrentseconds() - pause_start_seconds;
initial_seconds += pause_duration; // Shift the initial time to account for the pause duration.
}
}
}
private:
double initial_seconds = 0.0;
bool isPaused = false;
double pause_start_seconds = 0.0;
};

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
Expand Down Expand Up @@ -328,16 +366,10 @@ int real_main(int argc, char* argv[])
LogOutputName.clear();
LogDirectiveName.clear();
bool result = false, success;
bool was_paused = false;

double frame_duration;

double new_five_second_value = 0.0;
double actual_elapsed_time = 0;
double initial_seconds = 0;
double current_seconds = 0.0;
double paused_seconds = 0.0;
double sim_lag_time = 0;
double cycle_duration = 0.0;
double override_sim_rate_value = 0.0;
long sleep_nseconds = 0;
Expand Down Expand Up @@ -365,6 +397,10 @@ int real_main(int argc, char* argv[])
FDMExec->GetPropertyManager()->Tie("simulation/frame_start_time", &actual_elapsed_time);
FDMExec->GetPropertyManager()->Tie("simulation/cycle_duration", &cycle_duration);

Timer timer;
SGPropertyNode_ptr reset_node = FDMExec->GetPropertyManager()->GetNode("simulation/reset");
reset_node->addChangeListener(&timer);

// Check whether to disable console highlighting output on Windows.
// Support was added to Windows for Virtual Terminal codes by a particular
// Windows 10 release.
Expand Down Expand Up @@ -540,7 +576,7 @@ int real_main(int argc, char* argv[])
else sleep_nseconds = (sleep_period )*1e9; // 0.01 seconds

tzset();
current_seconds = initial_seconds = getcurrentseconds();
timer.start();

// *** CYCLIC EXECUTION LOOP, AND MESSAGE READING *** //
while (result && FDMExec->GetSimTime() <= end_time) {
Expand All @@ -560,20 +596,16 @@ int real_main(int argc, char* argv[])
if (play_nice) sim_nsleep(sleep_nseconds);

} else { // ------------ RUNNING IN REALTIME MODE
timer.pause(false);
actual_elapsed_time = timer.getElapsedTime();

double sim_lag_time = actual_elapsed_time - FDMExec->GetSimTime(); // How far behind sim-time is from actual elapsed time.
double cycle_start = getcurrentseconds();

// "was_paused" will be true if entering this "run" loop from a paused state.
if (was_paused) {
initial_seconds += paused_seconds;
was_paused = false;
}
current_seconds = getcurrentseconds(); // Seconds since 1 Jan 1970
actual_elapsed_time = current_seconds - initial_seconds; // Real world elapsed seconds since start
sim_lag_time = actual_elapsed_time - FDMExec->GetSimTime(); // How far behind sim-time is from actual
// elapsed time.
for (int i=0; i<(int)(sim_lag_time/frame_duration); i++) { // catch up sim time to actual elapsed time.
result = FDMExec->Run();
cycle_duration = getcurrentseconds() - current_seconds; // Calculate cycle duration
current_seconds = getcurrentseconds(); // Get new current_seconds
cycle_duration = getcurrentseconds() - cycle_start; // Calculate cycle duration
cycle_start = getcurrentseconds(); // Get new current_seconds
if (FDMExec->Holding()) break;
}

Expand All @@ -585,8 +617,7 @@ int real_main(int argc, char* argv[])
}
}
} else { // Suspended
was_paused = true;
paused_seconds = getcurrentseconds() - current_seconds;
timer.pause(true);
sim_nsleep(sleep_nseconds);
result = FDMExec->Run();
}
Expand Down
14 changes: 7 additions & 7 deletions src/simgear/props/props.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ public:
*/
virtual simgear::props::Type getType() const = 0;
virtual ~SGRaw() {}

/**
* Create a new deep copy of this raw value.
*
Expand All @@ -244,7 +244,7 @@ public:
class SGRawExtended : public SGRaw
{
public:
/**
/**
* Make an SGRawValueContainer from the SGRawValue.
*
* This is a virtual function of SGRawExtended so that
Expand Down Expand Up @@ -723,7 +723,7 @@ typedef std::vector<SGPropertyNode_ptr> PropertyList;
* <p>Any class that needs to listen for property changes must implement
* this interface.</p>
*/
class SGPropertyChangeListener
class JSBSIM_API SGPropertyChangeListener
{
public:
virtual ~SGPropertyChangeListener ();
Expand Down Expand Up @@ -1150,7 +1150,7 @@ public:
* Set all of the mode attributes for the property node.
*/
void setAttributes (int attr) { _attr = attr; }


//
// Leaf Value (primitive).
Expand Down Expand Up @@ -1284,7 +1284,7 @@ public:
{
return setValue(&val[0]);
}

/**
* Set relative node to given value and afterwards make read only.
*
Expand Down Expand Up @@ -1344,7 +1344,7 @@ public:
* Print the value of the property to a stream.
*/
std::ostream& printOn(std::ostream& stream) const;

//
// Data binding.
//
Expand Down Expand Up @@ -2136,4 +2136,4 @@ private:

#endif // __PROPS_HXX

// end of props.hxx
// end of props.hxx

0 comments on commit 5be7eab

Please sign in to comment.