Skip to content

Adding other vehicles to a scenario

Foretify's domain model has several predefined actors that represent Non-Principal Characters (NPCs). The following actors represent various types of vehicles.

  • vehicle
  • emergency_vehicle
  • car_group
  • box_truck
  • trailer

These actors have predefined attributes and scenarios that let you place them in a scenario and specify their size and behavior. The following sections show you how to add NPCs to a scenario.

Adding a single NPC with an active role to a scenario

To test the behavior of an SUT in an unusual situation or during an emergency, you might want to use the Foretellix behavioral modeling engine (BME) to allow the NPC to behave in unusual ways. You might even want to turn off the collision avoidance mechanism of the BME.

To add an active NPC to a scenario:

  1. Of the following SUMO configuration files, you must import the first file; the second is optional:

    • sumo_builtin_bme.osc defines Foretify's SUMO behavioral modeling engine.
    • sumo_demo_profiles.osc sets the parameters for demo profiles of sumo_idm_normal_driver and sumo_idm_aggressive_driver.
  2. Instantiate a parameterized SUMO driver model of your choice, for example:

    OSC2 code: Instantiate SUMO driver model
    dm: sumo_idm_normal_driver
    
  3. Constrain the vehicle.initial_bm field of the vehicle to the instantiated SUMO driver model.

    OSC2 code: constrain the vehicle to the model
    motorcycle: vehicle with:
        keep(it.category == motorcycle)
        keep(it.initial_bm == dm)
    
  4. Optionally, turn off the collision avoidance mechanism.

    OSC2 code: turn off collision avoidance behavior
    motorcycle_drive: motorcycle.drive() with:
        avoid_collisions(false)
    

Adding a motorcycle splitting the lanes

In this scenario, the SUT drives on a multi-lane road with a vehicle ahead of it and another vehicle on each side. A motorcycle approaches from behind along the lane boundary between the SUT and one of the vehicles to its side.

OSC2 code: motorcycle splitting lanes
import "$FTX/env/basic/exe_platforms/sumo_ssp/config/sumo_config.osc"
import "$FTX/env/basic/behavioral_models/sumo/builtin/sumo_builtin_bme.osc"
import "$FTX/env/basic/behavioral_models/sumo/common/sumo_demo_profiles.osc"

extend test_config:
    set map="$FTX_PACKAGES/maps/highway_2.xodr"
    set sumo_bm_lateral_resolution = 0.1meter  # Set smaller lateral res to allow bike pass between cars

extend top.main:
    path: one_way_road with:
        keep(it.min_lanes >= 3)
    dm: sumo_idm_normal_driver
    motorcycle: vehicle with:
        keep(it.vehicle_category == motorcycle)
        keep(it.initial_bm == dm)

    lead_vehicle: vehicle
    right_vehicle: vehicle
    left_vehicle: vehicle

    do parallel(duration:[20..30]second, overlap:equal):
        sut.car.drive() with:
            speed([20..50]kph, run_mode: best_effort)
            lane(middle: true, at: start)
            along(path)
        lead_vehicle.drive() with:
            position(time: [3..5]s, ahead_of: sut.car, at: start, time_tolerance: 1s)
            lane(same_as: sut.car)
            speed([20..50]kph, run_mode: best_effort)
        right_vehicle.drive() with:
            position(time: [2..3]s, ahead_of: sut.car, at: start, time_tolerance: 1s)
            lane(side_of: sut.car, side: right)
            speed([20..50]kph, run_mode: best_effort)
            along(path)
        left_vehicle.drive() with:
            position(time: [2..3]s, ahead_of: sut.car, at: start, time_tolerance: 1s)
            lane(side_of: sut.car, side: left)
            speed([20..50]kph, run_mode: best_effort)
            along(path)
        motorcycle_drive: motorcycle.drive() with:
            position(time: [2..4]s, behind: sut.car,
                measure_by: nearest, at: start, run_mode: best_effort)
            position([5..]meter, ahead_of: sut.car,
                measure_by: nearest, at: end, track: projected, tolerance: 2m)
            lane(same_as: sut.car, at: start, run_mode: best_effort)
            keep_lane(run_mode: best_effort)
            lateral(0m, line: left, run_mode: best_effort)
            avoid_collisions(false)

Adding vehicular traffic to a scenario

The most common use of the SUMO driver models is to add vehicular traffic to a scenario. To facilitate this, Foretify provides several car_group actors:

  • With the random_traffic_car_group actor, multiple vehicles are positioned relative to the initial position of an actor, typically the SUT. All vehicles start on any road and move on random routes at random speeds under the control of the simulator.
  • With the single_lane_car_group and all_lanes_car_group actor, multiple vehicles are positioned relative to a lead vehicle optionally controlled by Foretify. Other vehicles in the group are controlled by SUMO and move along the same route as the lead vehicle, either in a single-lane formation or a multi-lane formation.

For a description of the fields and movement scenarios of car_group actors, see the predefined car_group actor. You can also use the FTX driver to control car groups. For an example, see the ftx_group_driver_model struct documentation.

To add vehicular traffic to a scenario:

  1. Of the following SUMO configuration files, you must import the first file; the second is optional:

    • sumo_builtin_bme.osc defines Foretify's behavioral model engine.
    • sumo_demo_profiles.osc set the parameters for demo profiles of sumo_idm_normal_driver and sumo_idm_aggressive_driver.
  2. Instantiate either random_traffic_car_group, single_lane_car_group or all_lanes_car_group in the scenario.

    OSC2 code: instantiate car_group
    car_group: single_lane_car_group with(reference_car: lead_car):
        keep(it.cars.size() == 6)
    
  3. Instantiate a parameterized SUMO driver model of your choice.

    OSC2 code: instantiate a SUMO model
    dm: sumo_idm_normal_driver
    
  4. Constrain the vehicle.initial_bm field of each vehicle to the instantiated SUMO driver model.

    OSC2 code: constrain the vehicle to the model
    for car in car_group.cars:
        keep(car.initial_bm == dm)
    
  5. Use the movement scenarios defined in each actor to deploy the vehicles.

    OSC2 code: use group_drive()
    car_group_start: car_group.group_drive()
    

Adding random traffic

This example instantiates the random_traffic_car_group actor and uses its light_highway_traffic() scenario to deploy the vehicles.

OSC2 code: random_traffic_car_group
import "$FTX/config/sim/sumo_default.osc"
import "$FTX/env/basic/behavioral_models/sumo/builtin/sumo_builtin_bme.osc"
import "$FTX/env/basic/behavioral_models/sumo/common/sumo_demo_profiles.osc"

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

extend top.main:
    random_traffic: random_traffic_car_group with(origin_actor: sut.car)

    dm: sumo_idm_normal_driver
    for car in random_traffic.cars:
        keep(car.initial_bm == dm)

    do parallel(overlap:equal):
        dut_drive: sut.car.drive(duration: 10second) with:
            speed(20kph)
        random_traffic.light_highway_traffic()

Adding a group of cars with a common route

This example shows how to add a single_lane_car_group to a scenario. The method is the same for an all_lanes_car_group.

OSC2 code: single_lane_car_group
import "$FTX/config/sim/sumo_default.osc"
import "$FTX/env/basic/behavioral_models/sumo/builtin/sumo_builtin_bme.osc"
import "$FTX/env/basic/behavioral_models/sumo/common/sumo_demo_profiles.osc"

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

extend top.main:
    lead_vehicle: vehicle
    sut_cruise_speed: speed with:
      keep(default it == 90kph)
    hwy: highway
    car_group: single_lane_car_group with:
        keep(it.reference_car == sut.car)
        keep(it.cars.size() == 6)
        keep(it.reference_car_index == 4)

    dm: sumo_idm_aggressive_driver
    for car in car_group.cars:
        keep(car.initial_bm == dm)

    do parallel(overlap:equal):
            sut.car.drive() with:
                speed(speed: sut_cruise_speed)
                along(hwy)
            car_group_start: car_group.group_drive()
    with:
        duration([10..10]second)

Operating a vehicle's signals and lights

The scenarios shown in the table below let you turn on and off a vehicle's hazard light or turn signals:

Signature Description
vehicle.turn_signal_lights_state(signal_state: turn_signal_state) Set a vehicle's turn signal state to off, right_on or left_on. (The simulator may set the state to unknown if it cannot be determined or if turn signals are not supported.)
vehicle.turn_hazard_lights_state(hazard_lights_state: av_state) Set a vehicle's hazard lights to active or off.
OSC2 code: operate a vehicle's hazard lights
import "$FTX/config/sim/carla_default.osc"

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

extend top.main:
    car1: vehicle

    do serial():
        car1.turn_hazard_lights_state(active)
        p0: parallel(duration:[3..5]second, overlap:equal):
            e0: sut.car.drive()
            c0: car1.drive() with:
                position([10..20]m, behind: sut.car, at: start)

        car1.turn_hazard_lights_state(off)
        p1: parallel(duration:[3..5]second, overlap:equal):
            d0: sut.car.drive()
            car1.drive()
OSC2 code: operate a vehicle's turn signals
import "$FTX/config/sim/carla_default.osc"

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

extend top.main:
    car1: vehicle

    do serial():
        car1.turn_signal_lights_state(left_on)
        p0: parallel(duration:[3..5]second, overlap:equal):
            e0: sut.car.drive()
            c0: car1.drive() with:
                position([10..20]m, behind: sut.car, at: start)

        car1.turn_signal_lights_state(right_on)
        p1: parallel(duration:[3..5]second, overlap:equal):
            d0: sut.car.drive()
            car1.drive()