Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent time catch up in real time mode #1213

Merged
merged 4 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading