From d1e102ad6cb47e0ca1d39ff2ec51011abd242303 Mon Sep 17 00:00:00 2001 From: Joost Ellerbroek Date: Tue, 19 Jul 2022 14:47:43 +0200 Subject: [PATCH] split realtime timing from sim.step() --- BlueSky_pygame.py | 2 +- bluesky/network/detached.py | 6 +-- bluesky/network/node.py | 10 ++--- bluesky/simulation/screenio.py | 2 +- bluesky/simulation/simulation.py | 63 ++++++++++++++++++++------------ 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/BlueSky_pygame.py b/BlueSky_pygame.py index ed0afa2b4e..ce9eb8bb6a 100644 --- a/BlueSky_pygame.py +++ b/BlueSky_pygame.py @@ -15,7 +15,7 @@ def main(): # Main loop for BlueSky while not bs.sim.state == bs.END: - bs.sim.step() # Update sim + bs.sim.update() # Update sim bs.scr.update() # GUI update bs.sim.quit() diff --git a/bluesky/network/detached.py b/bluesky/network/detached.py index 505b63bc64..99ee411399 100644 --- a/bluesky/network/detached.py +++ b/bluesky/network/detached.py @@ -10,8 +10,8 @@ def __init__(self, *args): self.host_id = b'' self.running = True - def step(self): - ''' Perform one iteration step. Reimplemented in Simulation. ''' + def update(self): + ''' Update timers. ''' # Process timers Timer.update_timers() @@ -28,7 +28,7 @@ def run(self): ''' Start the main loop of this node. ''' while self.running: # Perform a simulation step - self.step() + self.update() bs.sim.step() def connect(self): diff --git a/bluesky/network/node.py b/bluesky/network/node.py index 8c704d7a73..1b50c9e307 100644 --- a/bluesky/network/node.py +++ b/bluesky/network/node.py @@ -19,8 +19,8 @@ def __init__(self, event_port, stream_port): self.event_port = event_port self.stream_port = stream_port - def step(self): - ''' Perform one iteration step. Reimplemented in Simulation. ''' + def update(self): + ''' Update timers and perform I/O. ''' # Process timers Timer.update_timers() # Get new events from the I/O thread @@ -63,10 +63,10 @@ def run(self): ''' Start the main loop of this node. ''' while self.running: # Perform a simulation step - self.step() - bs.sim.step() + self.update() + bs.sim.update() # Update screen logic - bs.scr.step() + bs.scr.update() def addnodes(self, count=1): self.send_event(b'ADDNODES', count) diff --git a/bluesky/simulation/screenio.py b/bluesky/simulation/screenio.py index 9337e4e721..df845a7fb0 100644 --- a/bluesky/simulation/screenio.py +++ b/bluesky/simulation/screenio.py @@ -55,7 +55,7 @@ def __init__(self): self.fast_timer.timeout.connect(self.send_aircraft_data) self.fast_timer.start(int(1000 / self.acupdate_rate)) - def step(self): + def update(self): if bs.sim.state == bs.OP: self.samplecount += 1 diff --git a/bluesky/simulation/simulation.py b/bluesky/simulation/simulation.py index 289f9f6b2a..8ca13f24bb 100644 --- a/bluesky/simulation/simulation.py +++ b/bluesky/simulation/simulation.py @@ -53,24 +53,16 @@ def __init__(self): # Keep track of known clients self.clients = set() - def step(self): - ''' Perform a simulation timestep. ''' - # Simulation starts as soon as there is traffic, or pending commands + def step(self, dt_increment=0): + ''' Perform one simulation timestep. + + Call this function instead of update if you don't want to run with a fixed + real-time rate. + ''' if self.state == bs.INIT: - if self.syst < 0.0: - self.syst = time.time() - + # Simulation starts as soon as there is traffic, or pending commands if bs.traf.ntraf > 0 or len(bs.stack.get_scendata()[0]) > 0: self.op() - if self.benchdt > 0.0: - self.fastforward(self.benchdt) - self.bencht = time.time() - - # When running at a fixed rate, or when in hold/init, - # increment system time with sysdt and calculate remainder to sleep. - remainder = self.syst - time.time() - if (not self.ffmode or self.state != bs.OP) and remainder > MINSLEEP: - time.sleep(remainder) # Always update stack simstack.process() @@ -81,15 +73,8 @@ def step(self): datalog.update() simtime.preupdate() - # Determine interval towards next timestep - if remainder < 0.0 and self.rtmode: - # Allow a variable timestep when we are running realtime - self.simt, self.simdt = simtime.step(-remainder) - else: - # Don't accumulate delay when we aren't running realtime - if remainder < 0.0: - self.syst -= remainder - self.simt, self.simdt = simtime.step() + # Determine interval towards next timestep + self.simt, self.simdt = simtime.step(dt_increment) # Update UTC time self.utc += datetime.timedelta(seconds=self.simdt) @@ -98,6 +83,34 @@ def step(self): bs.traf.update() simtime.update() + def update(self): + ''' Perform a simulation update. + This involves performing a simulation step, and when running in real-time mode + (or a multiple thereof), sleeping an appropriate time. ''' + if self.state == bs.INIT: + if self.syst < 0.0: + self.syst = time.time() + + if self.benchdt > 0.0: + self.fastforward(self.benchdt) + self.bencht = time.time() + + # When running at a fixed rate, or when in hold/init, + # increment system time with sysdt and calculate remainder to sleep. + remainder = self.syst - time.time() + if (not self.ffmode or self.state != bs.OP) and remainder > MINSLEEP: + time.sleep(remainder) + + # Perform one simulation timestep + if remainder < 0.0 and self.rtmode: + # Allow a variable timestep when we are running realtime + self.step(-remainder) + else: + # Don't accumulate delay when we aren't running realtime + if remainder < 0: + self.syst -= remainder + self.step() + # Always update syst self.syst += self.simdt / self.dtmult @@ -111,6 +124,7 @@ def step(self): else: self.op() + # Inform main of our state change if self.state != self.prevstate: bs.net.send_event(b'STATECHANGE', self.state) @@ -179,6 +193,7 @@ def realtime(self, flag=None): def fastforward(self, nsec=None): ''' Run in fast-time (for nsec seconds if specified). ''' + self.state = bs.OP self.ffmode = True self.ffstop = (self.simt + nsec) if nsec else None