Force simulator to run in real time for external inputs

Hi,

I’m trying to figure out how to make the simulator run in “real-time”. As in, take in the Node input data over the course of time sim.run() is called. Is it possible for sim.run(20) runs 20 seconds instead of as fast as it can?

My external sensor data forces me to use the GUI to get around this issue, but it is not convienent.

Hi @nwzins,

You can definitely do this for sure. In addition to the run function, the nengo.Simulator object exposes a step function that runs the simulation for 1 timestep. You can use this step function in addition to some Python logic to get the Nengo simulation to run in real time, rather than as fast as the CPU can run it.

As a example (and this is a super quick example that will be a smidge slower than real time):

dt = 0.001
with nengo.Simulator(model, dt) as sim:
    while t < endtime:
        time.sleep(dt) # sleep for 1ms
        sim.step()
        t += dt

So, in the code above, assuming the sim.step() function runs significantly faster than 1ms, what Python will do is advance the Nengo simulator by 1 timestep (default of 1ms), then sleep for 1ms, and repeat the process until some endtime is reached (could also run indefinitely).

You can also create the simulator object outside of a context block so that you can pass it around to other Python functions. The only important thing to note here is you need to manually close the simulator when done:

dt = 0.001
sim = nengo.Simulator(model, dt)

# Inside some other Python function
def ...(sim, ...):
    while t < endtime:
        time.sleep(dt) # sleep for 1ms
        sim.step()
        t += dt

# Cleanup
sim.close()

You can combine this approach with asyncio or threading or processes to get the Nengo simulator to run in real time.

If the call to get the sensor data is blocking (i.e., stops the Python process until a successful read from the sensor is done), making Nengo run in real-time could be something as simple as such:

dt = 0.001
with nengo.Simulator(model, dt) as sim:
    while t < endtime:
        sensor.read()  # Read from the sensor, must be a blocking call
        sim.step()
        t += dt

Awesome, thank you so much for the help! I’ll have to look again but I’m getting the data from a ROS subscriber node and I don’t think its blocking.

1 Like

Hi @xchoo I don’t totally understand how a blocking sensor.read() call would force this to run at a desired rate, and not just the rate of the sensor.read() + sim.step() calls.

Hi @nwzins, yes. that would be the case. I was assuming the time taken to do sensor.read() was negligible compred to sim.step(). :laughing:
In actual fact, you’ll probably want encapsulate the sim.step and sensor.read() functions inside a callback thread, where a timer initiates the callback every dt seconds (or something similar).

1 Like

Thanks a bunch! Started off using asyncio but got it working much better using threading with a someones PeriodicTimer class to call the step function.

1 Like