Skip to content

487. Concepts

487.1 Actor state

The SSP API and the DSP API define the position and the state of an actor on the map using the global coordinates system. The state of each object is specified by the six degrees of freedom (6DoF): x, y, z, roll, pitch, yaw.

The underlying type of those fields is dependent on the context. For example, when specifying a position, x is measured in meters; whereas, for acceleration, x is measured in meters/sec^2.

487.1.1 Specifying an actor's state

On each step, Foretify queries the SSP for the state of all actors. For each actor, the SSP reports its current position, speed, and acceleration, in each of the 6DoF, as mentioned above. Because not all simulators can provide this information, some of the fields may be omitted. In those cases, Foretify calculates an approximation of them using the other given fields.

The only mandatory fields for specifying an actor's position are x and y. All other fields are optional. However, SSP implementors are encouraged to supply all the fields available in the simulator as it can improve Foretify's accuracy during scenario execution and provide more accurate data for coverage and metrics collection.

487.2 Actor movement

While executing a scenario, Foretify needs to update the traffic vehicles' trajectories to execute the generated scenario. There are three types of RPC that Foretify can send to set an actor trajectory: set_xy_trajectory, set_dynamic_move, and set_external_controller.

Note

If the actor is a vehicle, you must configure it appropriately. See Configuring vehicles.

487.2.1 set_xy_trajectory

The standard method Foretify uses to control an NPC trajectory is an array of x and y coordinates, which is referred to as kinematic movement.

The trajectory is updated every ~200ms and includes a set of coordinates for each of the upcoming simulation steps. The SSP is required to set the actor's position on each step by following the trajectory received from Foretify.

487.2.2 set_dynamic_move

Controlling an actor dynamically through throttle, brake, and steering controls is needed in the following cases:

  • Foretify controls an NPC that requires a natural moving profile.
  • Foretify's [Human Driver Model][foretellix-human-driver-model-api] controls the Ego vehicle during parts of the scenario and setting x and y positions for the Ego vehicle is not allowed.

The message includes an array of throttle/brake and steering values that should be applied to the simulator by the SSP on each step. (For a more detailed description, see the message definition.)

487.2.3 set_external_controller

set_external_controller is used to set a target destination for the NPC and to request that the simulator control it. Also, it contains a list of key-value string parameters that allow configuring of the actor according to the unique capabilities supported by the simulator.

487.3 Controlling the Ego vehicle

The flow for testing an Ego in an execution platform varies according to the characteristics of the features under test. The type of messages supported by the Ego is usually coupled with the level of autonomy implemented. Level 4 usually can only receive a target position, while Levels 2 and 3 often need a driver's simulation to control the vehicle at specific points in the scenario.

The messages below address the need to have several interface types. The actual messages that are sent depend on the loaded configuration of the SUT as defined in the OSC2 files and on the loaded scenario files.

Note

You must also configure the SUT vehicle appropriately. See Configuring vehicles.

487.3.1 set_ego_destination

Sets the requested destination point for the Ego vehicle. Foretify calls this method once at the beginning of the scenario.

487.3.2 set_dynamic_move

Sets a trajectory in the form of throttle/brake pedals and steering wheel commands to the vehicle actuators. Used on Levels 2 and 3 to simulate a driver co-controlling the Ego vehicle. The DSP may choose to override those values before passing them to the simulator.

487.4 Synchronization

Foretify, the simulator, and the SUT are three processes that interact with each other throughout the test execution. To allow a repeatable test environment, all communication between Foretify and the SSP/DSP is synchronized. Foretify blocks on each RPC until a response is received from the SSP and the DSP.

The design can lead to deadlocks as some simulator implementations wait for a command from all connected clients, or specifically as in this case, Foretify and the SUT. This behavior is especially common in two message types: start simulation and simulation step.

To overcome the deadlock, the SSP and DSP APIs include special handling for the following message types: "start_simulation", "step". Each of those messages is split into 2 separate calls:

  1. start_simulation

    • start_simulation - SSP/DSP should perform tasks required for starting a new simulation but should not wait for confirmation from the simulator.
    • wait_start_simulation - SSP/DSP should block until the simulation is ready to start.
  2. step

    • start_step - SSP/DSP should perform tasks to advance the simulation step. It should not block until the simulator has completed executing the step; instead, it should return immediately.
    • wait_step - SSP/DSP should block until simulation has reached the requested time step.

487.5 Foretify steps versus simulation steps

Foretify and simulator steps do not have to be fully aligned. It's possible to run simulation at a higher update rate (although not the other way around). Foretify steps control scenario execution, which includes:

  • Updating actor states based on simulation data

  • Updating running scenarios

  • Collecting coverage

  • Executing checkers

If Foretify is running at a lower frequency than simulation, Foretify will provide to SSP/DSP trajectory points based on simulation frequency (using interpolation). This means that simulation will happen at a higher rate and Foretify will only get partial data.

In the case of a difference in step, it's the responsibility of SSP to perform multiple simulation steps for a single Foretify step, meaning Foretify will call start_step and wait_step only for a Foretify step. If simulation frequency is higher, for example, if Foretify is configured with a step size of 20ms and the simulator runs with a step size of 5ms, for each Foretify step, SSP is expected to perform four simulation steps.

487.6 Passing custom data to simulator

Foretify lets you pass custom data to simulator in various messages. This data can be passed in a generic mechanism using key-value pairs of strings. Hooks that allow passing custom data to simulation include the following:

  • On startup (see [init_req]). You can implement the get_additional_sim_properties() method under av_sim_adapter.

  • On simulation start (see [start_simulation_req]). You can implement the get_additional_start_simulation_properties method under av_sim_adapter.

  • On end simulation (see [end_simulation_req]). You can implement the invoke_get_additional_end_simulation_properties method under av_sim_adapter.

Example

This example shows how to send additional custom data when initializing SSP.

OSC2 code: sending custom data during initialization
import "$FTX/env/basic/exe_platforms/model_ssp/config/model_dummy_config.osc"
import "$FTX/env/basic/msp/open_drive.osc"

extend test_config:
    set map = "$FTX_PACKAGES/maps/highway.xodr"


extend av_sim_adapter:
    def get_additional_sim_properties()-> list of property is also:
        var my_data : property = new
        my_data.name = "my_data_key"
        my_data.value = "my_data_value"
        result.add(my_data)


extend top.main:
    do sut.car.drive() with:
        duration([3..5]s, run_mode: best_effort)

This example shows how to send additional custom data when starting simulation.

OSC2 code: sending custom data when starting simulation
import "$FTX/env/basic/exe_platforms/model_ssp/config/model_dummy_config.osc"
import "$FTX/env/basic/msp/open_drive.osc"

extend test_config:
    set map = "$FTX_PACKAGES/maps/highway.xodr"


extend av_sim_adapter:
    def get_additional_start_simulation_properties()-> list of property is also:
        var my_data : property = new
        my_data.name = "my_data_key"
        my_data.value = "my_data_value"
        result.add(my_data)


extend top.main:
    do sut.car.drive() with:
        duration([3..5]s, run_mode: best_effort)

This example shows how to send additional custom data when ending simulation.

OSC2 code: sending custom data when ending simulation
import "$FTX/env/basic/exe_platforms/model_ssp/config/model_dummy_config.osc"
import "$FTX/env/basic/msp/open_drive.osc"

extend test_config:
    set map = "$FTX_PACKAGES/maps/highway.xodr"


extend av_sim_adapter:
    # Send main_issue_category property to the simulation
    def get_additional_end_simulation_properties()-> list of property is also:
        var main_issue_category : property = new
        main_issue_category.name = "main_issue_category"
        main_issue_category.value = "$(top.issues.main_issue.category)"
        result.add(main_issue_category)


extend top.main:
    do sut.car.drive() with:
        duration([3..5]s, run_mode: best_effort)

487.7 Message Bridge

The Foretify Message Bridge builds a Foretify-System bridge, where "System" is a publish-subscribe system such as ROS, ROS2 or DDS. You can use the Bridge to send messages "down" from Foretify to the SUT and "up" from the SUT to Foretify.

The Message Bridge was designed to bridge between Foretify and a System Under Test (SUT) based on a messaging framework ("System"), for seamless message passing between the two.

An SUT may be an autonomous vehicle software stack, Advanced Driver-Assistance System (ADAS) function, such as cruise control or automatic emergency braking, or any other system that needs testing. When an SUT uses a messaging protocol like ROS, ROS2 or DDS, you can use the Message Bridge to send messages "down" from Foretify to the SUT and "up" from the SUT to Foretify. Examples of down messages are sending a mission or destination to an AV stack, or an "on" command to an ADAS module. Examples of up messages are internal status messages of AV modules that you can use in white-box checks or KPIs in OSC2 code.

Currently the message bridge supports the following protocols:

  • ROS
  • ROS2
  • DDS

The Message Bridge contains a build script whose input is a JSON config file that points to message definitions. The script generates and builds code that converts between OSC2 and System types and sends messages via the SUT Support Package (DSP) fRPC API.

On the Foretify side, the Bridge consists of OSC2 files with message struct definitions, and C++ conversion code. The OSC2 code also defines events that can be either:

  • Emitted in scenarios to send messages down.
  • Acted on when messages arrive up.

On the DSP side, the Bridge script generates a complete skeleton C++ DSP that acts as a node in the System, publishing and subscribing to the specified message topics.

Figure 1 shows the Message Bridge architecture, where

  1. Down messages are created as manually emitted events in OSC2, and get published in the SUT System.
  2. Up messages are received from the SUT System and get emitted as events in OSC.
Figure 1: Message Bridge Architecture

487.7.1 Current release

  • ROS1 (melodic/kinetic), ROS2 (dashing/foxy), and RTI DDS are supported at this time.

  • Only ROS topics are supported. In the future ROS services will be supported.

  • When specifying the kind of vehicle, you must choose sut or traffic. In the future, other_name will be added to support a custom OSC2 actor label.

  • Most basic ROS types are supported:

ROS/ROS2 type Corrresponding OSC2 type
string string
float32 real
float64 real
int8 (ROS2 only) int
int16 (ROS2 only) int
int32 int
int64 int
uint8 (ROS2 only) uint
uint16 (ROS2 only) uint
uint32 uint
uint64 uint
byte (ROS2 only) uint
bool bool
time time
geometry_msgs/Point (ROS1 only) msp_coordinates
array list
  • Most basic DDS types are supported:
DDS type Corrresponding OSC2 type
string string
float real
double real
int8 int
int16 int
int32 int
int64 int
long long int
uint8 uint
uint16 uint
uint32 uint
uint64 uint
octet uint
boolean bool
sequence list

487.7.2 Message Bridge components

The Message Bridge build script generates code as 2 separate components, as visualized in Figure 1:

  1. Foretify component
    • OSC2 struct representations of all defined messages
    • OSC2 events for each down and up message
    • C++ code to serialize OSC messages to send to the DSP
    • C++ code to deserialize messages from the DSP into OSC
    • The C++ code is built as a .so shared library which is linked to Foretify
  2. DSP component
    • C++ publish/subscribe code for all defined messages
    • C++ code to serialize received System messages to send to Foretify
    • C++ code to deserialize and publish messages received from Foretify
    • Also includes a skeleton full DSP that fulfills the DSP API
    • The DSP is built as an executable that is called from a shell script

For more details, see Use the Message Bridge.

487.8 Maps

Foretify currently allows loading only OpenDRIVE maps.

However, it can still integrate with a simulator and an SUT that uses different map formats. For that, the following conditions must be met:

  • The other map format supports a representation of road geometry using a global coordinate system.
  • There is an external conversion tool that can create matching representations of the same map in both formats.
  • After conversion, both map formats remain consistent in their global coordinates representation.

In cases in which the last two conditions are not met, it is possible to implement a component named Map Support Package (MSP). With this interface, Foretify is able to load the new map format. The specification of the MSP is not covered in this document.

487.9 Coordinate System

Foretify's Inertial Coordinate System defines position in relation to an arbitrary point that is defined by the loaded map. Foretify uses this system when communicating with external components such as a simulator or a SUT, so any data stored or calculated externally and returned by an external agent or method is defined in this system. All Simulator Support Package (SSP) and SUT Support Package (DSP) APIs use this system.

The definition of this system is based on the ISO 8855 standard. This system, like most coordinate systems, follows the right-handed rule for curve orientation. This means that motion around any axis is counter-clockwise, as opposed to left-hand systems where that motion is clockwise. Thus, curved motion is defined in this system using the following convention:

  • Positive curvature is a left curve (counter-clockwise motion)

  • Negative curvature is a right curve (clockwise motion)

For more details, see Foretify's coordinate system.

487.9.1 Definition of axes

The X and Y axes are parallel to the ground plane and the Z axis points upward. When used within a geographic reference, the following convention applies:

  • X - East

  • Y - North

  • Z - Up

487.9.2 Origin point

The origin point for the system is arbitrary and defined by the loaded map.

487.9.3 Angles

  • Yaw - around the Z axis, 0.0 = in the direction of the X axis (east, counterclockwise)

  • Pitch - around the Y axis, 0.0 = level (in the X/Y plane)

  • Roll - around X axis, 0.0 = level (parallel to the X/Y plane)

487.9.4 Example usage

Using the three coordinates and the three rotation angles of this system, Foretify specifies the precise position and orientation of an actor. Users can see these global coordinates when tracing, for example, a vehicle’s state.

Foretify output
[INFO] [TRACER] [0.020] trace:
car1.state.msp_pos.global_position.coord.x=-693.678
car1.state.msp_pos.global_position.coord.y=338.14
car1.state.msp_pos.global_position.coord.z=0
car1.state.msp_pos.global_position.rotation.roll=0
car1.state.msp_pos.global_position.rotation.yaw=13.20
car1.state.msp_pos.global_position.rotation.pitch=0
For more details, see Foretify's coordinate system.

487.10 Model SSP mock simulator

Model SSP is a lightweight mock simulator developed by Foretellix for rapid scenario prototyping and large-scale testing. It is faster and more resource-efficient than a real simulator. You can use Model SSP instead of a target simulator (for example, CARLA) to quickly analyze scenario quality, identify incomplete scenarios or tool errors, perform coverage analysis, and validate checks.

See Model SSP for more details.