.. index:: pair: page; NRPCoreSim .. _doxid-nrp_simulation: NRPCoreSim ========== This is the main NRP-core executable. It can be used to run an experiment locally. With it, a simulation is configured, a Simulation Loop is initialized, and a simulation is run. The process is divided into the following steps: * Parse input parameters: * If a ``-h`` or ``--help`` is added to the simulation, only print the help text, then exit * ``-d`` : the experiment folder location * ``-c`` : configuration file name, relative to ``-d`` or the folder NRPCoreSim is executed from * ``-o`` or ``--param`` : *Parameter=Value* pair, which :ref:`overrides the corresponding parameter ` from the configuration file * ``-p`` : Engine plugins to load. The expected value is a list of :ref:`engine plugin `.so libraries separated by commas without spaces and between quotation marks. If not present all the engine plugins compiled with nrp-core are loaded * Initialize the Python interpreter for TransceiverFunctions * Setup the process launchers * Load engine launchers: * Start the :ref:`EnginePluginManager ` * Load engine plugins * Store all engines launchers contained in the loaded plugins in an :ref:`EngineLauncherManager ` * Use input parameters to generate a new instance of :ref:`SimulationManager `. This will also launch all engine processes defined in the SimulationConfig passed to NRPCoreSim * Initialize the Simulation Loop and run until timeout The steps described above correspond to the so called ``standalone`` mode, in which an experiment is loaded, run until timeout and shutdown. NRPCoreSim can be started as well in ``server`` mode. See :ref:`below ` for more details. To launch an experiment with NRPCoreSim, the user must specify the simulation configuration file and optionally a list of engine plugins to be loaded. Eg: .. ref-code-block:: cpp NRPCoreSim -c simulation_config.json -p "NRPGazeboGrpcEngine.so,NRPNestJSONEngine.so,NRPNestServerEngine.so" .. _doxid-nrp_simulation_1cli_override_simulation_parameters: CLI for overriding configuration file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parameters in the simulation configuration file can be overridden from NRPCoreSim using the input parameter ``-o`` followed by the pair ``ParameterName=``. Multiple ``-o`` paramaters can be passed to NRPCoreSim. Similarly, several pairs separated by comma ``,`` can be passed after the input parameter ``-o``. Consequently, neither ``ParameterName`` nor ``NewValue`` can contain commas. Nested parameters are supported as well, you can separate nesting levels with dots, e.g. ``ParentParameter.ChildParameter=``. As many levels of nesting as required can be specified. Two cases are supported: * ``ParentParameter`` is a dictionary: in this case ``ChildParameter`` is expected to be a key in the dictionary * ``ParentParameter`` is an array: ``ChildParameter`` is an integer indicating the index of the array to be overridden, or a pair Key:Value that is used for the searching of a required element. The ```` is parsed as JSON, thus, the proper numerical or boolean values can be substituted into the configuration file. In case a string is used as the new value, then it should be enclosed in escaped double quotes. As an example, if the configuration to override parameters from looks like: .. ref-code-block:: cpp { "SimpleParameter": "OldValue1", "ListName" : [ { "NestedParameter1": "value1", "NestedParameter2": ["A", "B", "C"] }, { "NestedParameter1": "value3" } ], "DictName" : { "ImportantParameter": 1, "NonImportantParameter": "value2" } } then the following command .. ref-code-block:: cpp NRPCoreSim -c simulation_config.json -o SimpleParameter=\"NewValue\",DictName.ImportantParameter=2 -o ListName.NestedParameter1:value3.NewParameter1=false -o ListName.0.NestedParameter2.2=\"D\" will override the simulation configuration as .. ref-code-block:: cpp { "SimpleParameter": "NewValue", "ListName" : [ { "NestedParameter1": "value1", "NestedParameter2": ["A", "B", "D"] }, { "NestedParameter1": "value0", "NewParameter1": false } ], "DictName" : { "ImportantParameter": 2, "NonImportantParameter": "value2" } } :ref:`Default parameters ` in the simulation configuration schema can't be overridden. .. _doxid-nrp_simulation_1server_mode: Server Mode ~~~~~~~~~~~ NRPCoreSim can be launched in server mode by using the ``-m`` command line parameter. It can take two values, ``standalone``, which launched an experiment as described at the top of the page, or ``server``. In server mode NRPCoreSim opens a GRPC server which allows to control the experiment remotely. In this case, a :ref:`SimulationManager ` is created from the experiment configuration passed to NRPCoreSim. GRPC services are created which enable requests for transitions in the :ref:`Experiment Lifecycle `. The available services in the GRPC server, are: * :ref:`initialize() ` : initializes the simulation. Transitions to state ``Initialized``. * runLoop(int number_of_iterations): run the simulation loop for the specified number of iterations. Transitions to state ``Stopped``. * runUntilTimeout(): run the simulation loop until reaching timeout, as specified in the :ref:`configuration file `. Transitions to state ``Stopped``. * stop(): requests to stop a running simulation. * :ref:`reset() ` : resets an initialized simulation. * :ref:`shutdown() ` : shutdown the simulation. Transitions to state ``Created``. Each of these services are blocking, i.e. they only return after the request has been fully processed and the experiment has transitioned to the corresponding end state. With one exception, *stop()* can be called and processed in parallel with other service calls. This is because *stop()* is implemented as a signal for :ref:`SimulationManager ` to request to stop a running simulation. By itself *stop()* doesn't cause any transition in the experiment lifecycle, but it triggers a signal which will be caught by :ref:`SimulationManager ` which will stop the simulation if it was running. Other services which deserve some explanation are *runLoop()* and *runUntilTimeout()*. These have a slightly different behavior depending on whether :ref:`SimulationManager ` is managing an :ref:`FTILoop ` or an :ref:`EventLoop `. In the former case, *runLoop()* will effectively advance the simulation time by the specified number of iterations multiplied by the simulation timestep. runUntilTimeout() will run the simulation until it reaches timeout, starting from the simulation time when the service was called. Therefore calling *runLoop()* before calling *runUntilTimeout()* will reduce the total amount of (simulation) time the experiment is run for when the latter service is called. Also calling *runUntilTimeout()* after timeout has been reached will have no effect. runLoop() doesn't takes timeout into consideration and therefore will run the simulation loop for the specified number of iterations even after timeout is reached. The experiment simulation time is reset to 0 after calling :ref:`reset() `. When running an :ref:`EventLoop `, since in this case there is no concept of simulation time, *runUntilTimeout()* will always run the experiment for the specified number of iterations multiplied by the event loop timestep, independently of whether *runLoop()* or *runUntilTimeout()* were called before. :ref:`reset() ` is not available when running an :ref:`EventLoop ` experiment. Finally, it is worth to remark that from each state of the :ref:`experiment lifecycle `, only a subset of the aforementioned requests can be processed and executed. These can be seen in the the diagram in the experiment lifecycle page just referred before. After starting NRPCoreSim the experiment is in state ``Created``. If an error occurs while processing a request, the experiment is transition to state ``Failed``, from which only ``shutdown`` is possible. Though the NRPCoreSim server can be brought up and used independently, it is more conveniently used along with the provided Python client. See this :ref:`page ` for more information on how to do this.