Create a simulator

PMP provides the ability to create a simulated system. Simulation can be used to simulate the behavior of a physical controller and plants for testing and validation. For instance, a customer can use a simulated system, which consist of a top-controller, a sub-controller and plant model that describes their system, to perform motion analysis before deploying it on physical hardware. The simulator can run on a client PC processor or can be deployed on a remote simulation server.

This guide provides step-by-step instructions on how to create a local simulated system with a top-controller and a sub-controller.

During this guide you will learn how to:

  • Use a system description file to create a simulated system.

  • Monitor the value of a signal using the PMP API.

  • Dispose of a simulated system.

Prerequisites

Before continuing with the quick-start guide, please make sure that the following prerequisites are met:

  • PMP should be installed with Simulator and Tooling features. Follow the Installation quick-start guide if this is not yet the case.

    A Typical installation includes the required Simulator and Tooling features.
  • The create a simulator quick start project files should be available. These files can be downloaded from Downloads.

    • System description file:
      A system description file system.xml, which describes the system properties and includes the controller’s description.
    • Controller description files:
      A top-controller (Arcas) controller_arcas_5eg.xml, which describes the controller’s main properties, such as templates, number of axes, processing blocks, updatables, and more.
      A sub-controller (Arcas FPGA) controller_arcas_5eg_slave.xml, which includes digital IOs.

System description

The System description file system.xml defines the simulator properties and the simulated controllers that make up the simulated system. The resulting system in visualized in Simulated system.

System description file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<System>
  <Properties>
    <Property Name="SimulatorCpuUtilization" Value="Greedy" />
    <Property Name="SimulatorRealTimeThreads" Value="2" />
    <Property Name="SimulatorSpeedFactor" Value="1.0" />
    <Property Name="SimulatorClientAddress" Value="localhost" />
  </Properties>
  <Controllers>
    <Controller Description=".\controller_arcas_5eg.xml" HardwareSerialNumber="1" Id="1">
      <Controller Description=".\controller_arcas_5eg_slave.xml" HardwareSerialNumber="2"/>
    </Controller>
  </Controllers>
</System>
Simulated system

Simulated system

Simulator creation

First, we create a PMP system that listens for available controllers on the specified IP address. We will run the simulator on the local machine so the IP address should be localhost.

1
2
var address = "localhost";
var system = new Pmp.System(address);
1
2
auto address = "localhost";
auto system = std::make_shared<Pmp::CSystem>(address);
1
2
address = "localhost"
system = Pmp.System(address)
1
2
address = 'localhost';
system = Pmp.System(address);

Create a simulated system using the provided system.xml.

1
2
var systemDescription = "C:\\your\\path\\to\\create-a-simulator\\configuration-files\\system.xml";
system.CreateControllersFromFile(systemDescription);
1
2
auto systemDescription = "C:\\your\\path\\to\\create-a-simulator\\configuration-files\\system.xml";
system->CreateControllersFromFile(systemDescription);
1
2
systemDescription = "C:\\your\\path\\to\\create-a-simulator\\configuration-files\\system.xml"
system.CreateControllersFromFile(systemDescription)
1
2
systemDescription = 'C:\\your\\path\\to\\create-a-simulator\\configuration-files\\system.xml';
system.CreateControllersFromFile(systemDescription);

Attention

Make sure to update the C:\your\path\to\ part of the absolute file paths to match your chosen locations.

Controllers are automatically discovered on a configurable discovery interval. In addition, it is possible to force discovery between intervals using the Discover method. Since the creation of the simulated Arcas controller can take some time, a loop is used to wait for the simulated Arcas to appear.

1
2
3
4
5
6
var topControllerName = "Arcas 5EG-1";
while (!system.Controllers.Keys.Contains(topControllerName))
{
    system.Discover();
    Thread.Sleep(100);
}
1
2
3
4
5
6
auto topControllerName = "Arcas 5EG-1";
while (system->GetControllers().count(topControllerName) == 0);
{
    system->Discover();
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
1
2
3
4
topControllerName = "Arcas 5EG-1"
while topControllerName not in system.Controllers.Keys:
    system.Discover()
    time.sleep(0.1)
1
2
3
4
5
topControllerName = 'Arcas 5EG-1';
while ~any(strcmp(string(ToCell(system.Controllers.Keys)), topControllerName))
  system.Discover();
  pause(1);
end

Top-controller state machine

The top-controller is governed by the Top-controller state machine. Any controller, both physical and simulated, will automatically transition to the Config state. The WaitState method can be used to wait for the transition to complete.

Note

Enumeration of the top- and sub-controllers can take some time depending on the complexity of the system and the amount of sub-controllers in the system.

1
2
topController = system.Controllers[topControllerName];
topController.WaitState(Pmp.TopControllerState.Config, 60.0);
1
2
topController = system->GetController(topControllerName);
topController->WaitState(Pmp::ETopControllerState::Config, 60.0);
1
2
topController = system.Controllers[topControllerName]
topController.WaitState(Pmp.TopControllerState.Config, 60.0)
1
2
topController = system.Controllers.Item(topControllerName);
topController.WaitState(Pmp.TopControllerState.Config, 60.0);

Now that the system has been enumerated we can set the controller state to Run to enable periodic task running. The WaitState method can be used to wait for the transition to complete.

Note

The Config to Run state transition can take some time depending on the complexity of the system and the amount of sub-controllers in the system.

1
2
topController.Run();
topController.WaitState(Pmp.TopControllerState.Run, 10.0);
1
2
topController->Run();
topController->WaitState(Pmp::ETopControllerState::Run, 10.0);
1
2
topController.Run()
topController.WaitState(Pmp.TopControllerState.Run, 10.0)
1
2
topController.Run();
topController.WaitState(Pmp.TopControllerState.Run, 10.0);

Verification

By default, the sample frequency of the Arcas 5EG-1 is 2kHz. To verify that the top-controller periodic tasks are enabled, monitor the incrementing of the SampleCount signal.

Note

The simulator is sample-accurate, but not time-accurate. This means that all samples are calculated as if the sample frequency is 2kHz, however the exact SampleCount increment per second can deviate from 2,000 counts per second based on the available performance on the computer the simulator is running on.

1
2
3
4
5
for (int i = 0; i < 10; i++)
{
    Console.WriteLine("SampleCount: {0}", topController.Signals["SampleCount"].ValueUint32);
    Thread.Sleep(1000);
}
1
2
3
4
5
for (int i = 0; i < 10; i++)
{
    std::cout << "SampleCount: " << topController->GetSignal("SampleCount")->ReadUint32() << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
1
2
3
for i in range(10):
    print(f'SampleCount: {topController.Signals["SampleCount"].ValueUint32}')
    time.sleep(1)
1
2
3
4
for i = 1:10
    fprintf('SampleCount %d.\n',topController.Signals.Item('SampleCount').ValueUint32);
    pause(1);
end

Clean-up

Now that the verification is completed we can clean-up the simulator. To stop the controller and disable periodic task running, set the controller state to Config.

1
2
topController.Stop();
topController.WaitState(Pmp.TopControllerState.Config, 10.0);
1
2
topController->Stop();
topController->WaitState(Pmp::ETopControllerState::Config, 10.0);
1
2
topController.Stop()
topController.WaitState(Pmp.TopControllerState.Config, 10.0)
1
2
topController.Stop();
topController.WaitState(Pmp.TopControllerState.Config, 10.0);

To clean up the simulator, the following code can be used:

1
topController?.Dispose();
1
2
3
4
if(topController != nullptr)
{
    topController->Destroy();
}
1
2
if topController != None:
    topController.Dispose()
1
2
3
if not(isempty(topController))
    topController.Dispose();
end

Note

Closing the test application does not destroy the simulator. The simulator keeps running until it is explicitly destroyed.

See also

Simulation

Explanation of a system simulation concept and its purpose in the motion software.

System description

For more information on system descriptions.

Configuration

For more information on controller configuration.