Skip to main content

AVxcelerate Simulation Framework 2025 R2 SP02

Implement and use a standalone activity

Last update: 19.09.2025

Simulation Framework provides the possibility to inject any custom logic into a standalone activity, which is a separate process running outside simfwk_cli, but is able to connect with the simfwk core and communicate with other activities.

Interfaces and topic definition in RefSim

To implement one customized standalone activity, you need to have a look on essential interfaces: core/lifecycle/activity/base_activity.h , core/service/standalone_activity_service/standalone_activity_service.h , core/service/standalone_activity_service/standalone_activity_creator/i_standalone_activity_creator.h and topic definitions core/communication/topic_registry.h .

BaseActivity is the basic implementation of IActivity interface and used as base class of all customized activities. Inheriting classes, i.e. a concrete simulation activity, should implement their logic in ExecuteStep() and add needed pub/sub in AddPublisherAndSubscriber() method to achieve communications between others.

IStandaloneActivityCreator is the interface class for creating a standalone activity service. It defines how a customized activity needs to be instantiated through or not through StandaloneInitData.

StandaloneActivityService provides a running process of desired activity returned by interface IStandaloneActivityCreator and keeps it communicating and being scheduled by Simulation Framework core process.

topic_registry is a dedicated namespace where defines list of concrete Topics that can be used for creation of communication channels with given underlying message. As default, DDS message/communication type will be applied. The name of Topic ( TopicId ), which is passed into constructor to Topic, is globally unique and represents one single Topic, the underlying message could be the same though.

Currently following Topics and Message Type are available to use with Simulation Framework core library:

Topic Id (string) C++ Topic Type Underlying DDS Message Type Info
KpiLoggerTopic KpiMessageTopicType rtidds::KpiMessage Message to KpiLoggerActivity, each KpiContent inside KpiMessage will be logged into json
DriverInputTopic KpiMessageTopicType rtidds::KpiMessage Message to KpiLoggerActivity as type 'log', to mimic driver behaviour data only
SensorViewTopic GenericBytesTopicType rtidds::GenericBytesMessage Message to store osi SensorView protobuf message as bytes array
TrafficUpdateTopic GenericBytesTopicType rtidds::GenericBytesMessage Message to store osi TrafficUpdate protobuf message as bytes array
TrafficCommandTopic GenericBytesTopicType rtidds::GenericBytesMessage Message to store osi TrafficCommand protobuf message as bytes array

Limitation of topic

As mentioned in the sections above, activities can exchange data using messages through Topics. Users must be careful to ensure deterministic behavior of the simulation. This means that one Topic should have only one publisher. The issue with having multiple publishers on the same topic is that the first message from the faster publisher may arrive on the subscriber side and get consumed, while the second message from the slower publisher might be neglected. Hence, Simulation Framework enforces a "single publisher only" to ensure deterministic behavior of the simulation. If multiple publishers for one topic are instantiated, an exception will be thrown to prevent this.

Customize your topic

By means of any existing message type provided by core/communication/topic_registry.h, you can create any Topic you need for your simulations. Example of creating a new Topic with Message Type rtidds::GenericBytesMessage in one line:

auto your_topic = std::make_shared<Topic<rtidds::GenericBytesMessage>>("YourTopicId");

After that, your_topic is ready to be used to instantiate your activities.

Create a Topic using GenericBytesMessage

rtidds::GenericBytesMessage is a generic message type which allows users to put any content as a serialized byte array. E.g. GenericBytesTopicType, which stores the OSI protobuf message as underlying payload, is a good example to show how this mechanism works out. If you have a protobuf message which you want to send, you only need to call protobuf C++ API like following:

YourProtobufMessage protobuf_msg;
rtidds::GenericBytesMessage generic_msg{};
generic_msg.timestamp().seconds(1);
generic_msg.timestamp().nanoseconds(0)
size_t size = protobuf_msg.ByteSizeLong();
std::vector<unsigned char> proto_data_in_bytes;
proto_data_in_bytes.resize(size);
protobuf_msg.SerializeToArray(proto_data_in_bytes.data(), size);
generic_msg.size(size);
generic_msg.bytes_array(proto_data_in_bytes);

Then you will have a filled GenericBytesMessage generic_msg with your desired content and can publish it into the Topic defined with "YourTopicId".

On the subscriber side, you just need to decode the message from bytes array.

YourProtobufMessage protobuf_msg;
if (!protobuf_msg.ParseFromArray(generic_msg.bytes_array().data(),
generic_msg.size()))
{
throw std::runtime_error("Error parsing proto msg from bytes array in generic_msg! ");
}
ProcessYourProtoMsg(protobuf_msg);

For complete implementation example into your simulation, please refer /example/my_customized_topic/my_activities.h after installation.

Example standalone activity

There is an example implementation of Standalone Activity provided by the Simulation Framework delivery, namely simulation_framework/example/my_activity/my_activity.h . This Activity can be executed independently from simfwk_cli , and they will wait for simulation requests from simfwk_cli if they are selected in the simulation config.

Following the code API documentation and instruction in the comments of this example implementation, you can learn how to build your own Activity step by step and use it in a simulation.

Use one standalone activity

You can use the example standalone activity my_test_activity by defining the following JSON content in simulation_scheduling.

{
"sim_instance_name": "simulation_config_uses_my_test_activity",
"foxglove":
{
"data_streaming": true,
"host_name": "localhost",
"port": 8700,
},
"save_mcap": true,
"activities": [
{
"name": "groundtruth_generator_activity",
"is_primary_activity": true,
"topics_cycling_info": [
{
"topic_id": "__all__",
"topic_cycle_time_in_ms": 100
}
],
"type": "built-in"
},
{
"name": "driver_model_activity",
"depends_on": [
"groundtruth_generator_activity"
],
"type": "built-in"
},
{
"name": "my_test_activity",
"depends_on": [
"groundtruth_generator_activity"
],
"type": "standalone"
},
{
"name": "kpi_evaluator_activity",
"depends_on": [
"groundtruth_generator_activity"
],
"type": "built-in"
},
{
"name": "kpi_logger_activity",
"depends_on": [
"kpi_evaluator_activity"
],
"type": "built-in"
}
]
}

and use it in a simulation by running simfwk_cli:

./simfwk_cli -s my_config.json

Access Global Static Parameters and Timestamp

The IActivity interface and its derived class, core/lifecycle/activity/base_activity.h, provide several APIs to retrieve information related to the current simulation context. These include the current simulation timestamp, the cycle time for an activity, the simulation output directories, and input files. Available APIs are as follows:

Simulation timestamp

This API returns the current simulation timestamp, allowing your logic to access the exact simulation time at any given moment during execution.

time::Timestamp GetCurrentTimestamp() const final;

Cycle time

This API returns the cycle time for this activity, based on the scheduling configuration you have provided for simulation.

std::chrono::milliseconds GetCycleTime() const final;

Simulation output directory

This API returns the directory path where the outputs of the simulation are stored.

std::string GetSimulationOutputDirectory() const final;

4. Customized parameter from comamnd line

This API returns the customized parameters for the simulation as a map.

const SimulationParameters::CustomizedParameters& GetCustomizedParameters() const final;

In Simulation Framework Autonomy, three common input files, i.e. open scenario, driver input and user settings are assigned as "customized parameters" to the whole simulation and they can be retrieved by above API without any issue if the solver settings are correctly provided. The predefined names of these three common inputs can be found here autonomy/simulation/sim_instance/simulation_input_definition.h. To ensure any other custom input files or parameters are available via this API, they must be provided through CLI arguments using the pattern "name:value". For more instructions, please see command line tool

Connect with Ansys