Roadrunner Scenario Simulating
MathWorksOfficialCreated by MathWorks
- Skill
- Tool integration
- Science and research
- BSD-2-Clause
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides technical guidance for integrating RoadRunner scenario simulations with MATLAB and Simulink. It covers programmatic control of simulations, including running, stepping, and monitoring scenarios. It also details how to implement co-simulation by controlling actors via MATLAB System objects or Simulink models, attaching sensors, and retrieving simulation logs or scenario variables.
What it does
- Run and step through RoadRunner scenario simulations programmatically
- Control actor behavior during co-simulation using MATLAB or Simulink
- Attach and configure driving sensors to actors for data collection
- Retrieve and log simulation state, actor attributes, and scenario variables
- Monitor simulation progress and events using observers
- Publish Simulink models as actor behaviors for RoadRunner integration
When to use it
- When you need to automate the execution of RoadRunner scenarios
- When you require frame-by-frame simulation control or programmatic log access
- When implementing custom actor behaviors in MATLAB or Simulink
- When you need to integrate sensor data or monitor simulation state externally
Advantages
- Enables programmatic interaction with RoadRunner scenarios
- Supports complex co-simulation workflows with Simulink and MATLAB
- Provides granular control over simulation timing and actor attributes
- Facilitates automated data collection and sensor-based analysis
Usage examples
- “How do I step through a RoadRunner scenario in MATLAB?”
- Use createSimulation to get a handle, then call simulateScenario with IsSteppingStart=true, and use set(rrSim, SimulationCommand='Step') within a loop.
- “How can I control an actor using a MATLAB System object?”
- Assign a behavior asset to the actor, create a System object that finds the actor via Simulink.ScenarioSimulation.find, and use setAttribute to modify actor state.
- “How do I add a sensor to an actor in my simulation?”
- Obtain the SensorSimulation object from your simulation handle and use addSensors to attach configured sensor objects to a specific actor ID.
- “How do I start a co-simulation with a Simulink model?”
- Publish your model as a behavior, assign it to an actor in RoadRunner, and start the simulation using set_param('myModel', SimulationCommand='start').
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/matlab/roadrunner-scenario-simulating/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip roadrunner-scenario-simulating.zip -d .agents/skills
Documentation by MathWorks
RoadRunner Scenario Simulation
Simulate RoadRunner scenarios, step through simulations, control actors in co-simulation, add observers, attach sensors, and retrieve results — from MATLAB and Simulink.
When to Use
User wants to run a RoadRunner scenario simulation
User wants to step through a simulation frame-by-frame
User wants to control an actor externally (co-simulation)
User wants to observe simulation state (read-only monitoring)
User wants to add sensors and read target poses or lane boundaries
User wants to retrieve simulation logs programmatically
User wants to read or write scenario variables
User asks about co-simulation with Simulink
User asks about publishing actor behaviors
When NOT to Use
Launching or connecting to RoadRunner
Authoring scenarios (adding actors, paths, behaviors in the editor)
Building or editing scenes (roads, terrain, assets)
Exporting actor trajectories to CSV — use
exportActorTrajectoryToCSVdirectlyWorking with
drivingScenario(that is a DIFFERENT toolbox — Automated Driving Toolbox)
Critical: Do NOT Confuse With drivingScenario
drivingScenario (from Automated Driving Toolbox) is a MATLAB-native scenario tool.
RoadRunner Scenario simulation uses completely different APIs on the roadrunner object.
Never mix these two — they are unrelated.
Decision Tree
User wants to simulate →
├── Just run to completion? → Workflow A (simulateScenario)
├── Need step control OR programmatic log? → Workflow B (createSimulation)
├── Need to read actor state during sim? → Workflow C (getAttribute)
├── Need external actor control? →
│ ├── From MATLAB? → Workflow D (System object co-sim)
│ └── From Simulink? → Workflow E (Simulink blocks)
├── Need read-only monitoring? → Workflow F (Observers)
└── Need sensor data during sim? → Workflow G (SensorSimulation)Workflow A: Simple Simulation (run to completion)
Use when the user just wants to simulate an already-open scenario:
openScenario(rrApp, "MyScenario");
simulateScenario(rrApp, EnableLogging=true);Options: Pacing, IsBlocking, IsSteppingStart, EnableLogging.
Important: simulateScenario does NOT return a log object. Use it when you only need to run to completion. If you need programmatic access to the simulation log in MATLAB, use createSimulation (Workflow B) instead.
Workflow B: Step-by-Step Simulation
Use when the user needs frame-by-frame control or programmatic log access.
CRITICAL call order: createSimulation must be called BEFORE simulateScenario. The Scenario Server rejects new connections while a simulation is running or paused. Also, do NOT use set(rrSim, SimulationCommand="Start") then "Step" — "Start" runs the sim freely to completion.
% 1. Get the simulation handle FIRST (before anything is running)
rrSim = createSimulation(rrApp);
stepSize = 0.01;
set(rrSim, StepSize=stepSize);
set(rrSim, MaxSimulationTime=30);
% 2. THEN start simulation in stepping mode
simulateScenario(rrApp, IsSteppingStart=true, IsBlocking=false, EnableLogging=true);
pause(0.5); % Allow sim to initialize before stepping
% 3. Step through the simulation
for i = 1:numSteps
set(rrSim, SimulationCommand="Step");
pause(stepSize); % REQUIRED — Step is async, must wait for frame to complete
end
set(rrSim, SimulationCommand="Stop");
simLog = get(rrSim, "SimulationLog");CRITICAL: "Step" is asynchronous — you MUST add pause(stepSize) after each Step. Without it, commands pile up and are silently dropped. Do NOT use dot-method syntax (rrSim.step()) — always use set(rrSim, SimulationCommand=...). Do NOT set Logging="On" during stepping — use EnableLogging=true in the simulateScenario call.
SimulationCommand values
"Start", "Step", "Pause", "Continue", "Stop", "Replay"
Replay uses positional syntax: set(rrSim, "SimulationCommand", "Replay", fileName)
Polling SimulationStatus
get(rrSim, "SimulationStatus") returns: "Inactive", "Running", "Paused", "Done"
Use in wait loops when running non-blocking simulations. Check BOTH "Done" and "Inactive" — short scenarios may transition past "Done" before the poll catches it:
status = get(rrSim, "SimulationStatus");
while ~ismember(status, ["Done", "Inactive"])
pause(0.1);
status = get(rrSim, "SimulationStatus");
endWorkflow C: Reading Actor State
To get actor information during a step-by-step simulation:
Note: get(rrSim, "ActorSimulation") always includes the world actor (ID 0) at index 1. This is a non-movable root actor, not a vehicle. Skip it or filter by ID when iterating.
Note: Actors are only queryable while the simulation is active (Running or Paused). After "Stop", get(rrSim, "ActorSimulation") returns empty.
% Get all actors — returns a CELL ARRAY, use {idx} not (idx)
actors = get(rrSim, "ActorSimulation");
actorSim = actors{2}; % cell indexing required; index 1 is world actor (ID 0)
% Or find a specific actor by ID (returns a single object)
% NOTE: ActorID must be uint64 — double will fail silently or error
actorSim = Simulink.ScenarioSimulation.find("ActorSimulation", ActorID=uint64(1));
% Read runtime attributes — use getAttribute, NOT property access
pose = getAttribute(actorSim, "Pose"); % 4x4 matrix
velocity = getAttribute(actorSim, "Velocity"); % 1x3 vector
angVel = getAttribute(actorSim, "AngularVelocity"); % 1x3 vectorCRITICAL: Do NOT use actorSim.Pose or actorSim.Velocity — these are NOT public properties. Always use getAttribute(actorSim, "AttrName").
Runtime attributes: "ID", "Pose", "Velocity", "AngularVelocity", "WheelPoses", "LaneLocation", "Children", "Parent", "PhaseStatus", "ActorType", "TrafficSignalRuntime", "TrafficSignalControllerRuntime"
Static Attributes (Name, BoundingBox, etc.)
To get an actor's name or other static properties, use ActorModel — NOT getAttribute(actorSim, "Name") (which does not exist):
actorModel = get(actorSim, "ActorModel");
actorName = getAttribute(actorModel, "Name");
boundingBox = getAttribute(actorModel, "BoundingBox");Static attributes on ActorModel: "ID", "Name", "PaintColor", "BoundingBox", "WheelSpec", "TrafficSignalSpec", "TrafficSignalControllerSpec"
Workflow D: Co-Simulation with MATLAB System Object
Architecture
Assign a behavior to the actor (see below)
In MATLAB: Write a System object that controls the actor at runtime
The System object finds itself using
Simulink.ScenarioSimulation.find
Assigning Behaviors
R2024a: Assign behaviors in the RoadRunner Scenario Editor UI only (no MATLAB API).
R2025a+: Assign behaviors programmatically via the roadrunnerAPI authoring interface:
rrApi = roadrunnerAPI(rrApp);
prj = rrApi.Project;
scnro = rrApi.Scenario;
% Get or create a behavior asset
behaviorAsset = getAsset(prj, "Behaviors/MyBehavior.rrbehavior", "BehaviorAsset");
% Assign to an existing actor
car.BehaviorAsset = behaviorAsset;Key points:
roadrunnerAPI(rrApp)provides access toProjectandScenarioobjectsUse
getAsset(prj, path, "BehaviorAsset")to retrieve existing.rrbehaviorassetsUse
createAsset(prj, path, "BehaviorAsset")to create new behavior assetsAfter creating a behavior asset, set its platform:
setPlatform(behaviorAsset, "SimulinkPlatform")— this is correct for BOTH MATLAB System objects and Simulink models. Do NOT use"MATLAB","External", or"MATLABSystem"(they are not registered)Assign via the
BehaviorAssetproperty onVehicle/Character/MovableObjectThere is NO
setBehavior()function — use property assignment instead
System Object Pattern
classdef MyActorController < matlab.System
properties (Access = private)
ActorSim % ActorSimulation handle
end
methods (Access = protected)
function setupImpl(obj)
obj.ActorSim = Simulink.ScenarioSimulation.find( ...
"ActorSimulation", SystemObject=obj);
end
function stepImpl(obj)
action = getAction(obj.ActorSim, "PathAction");
currentPose = getAttribute(obj.ActorSim, "Pose");
% Modify pose
currentPose(1,4) = currentPose(1,4) + 0.5;
setAttribute(obj.ActorSim, Pose=currentPose);
% Signal action completion (guard: ActionID may not exist)
if ~isempty(action) && isfield(action, "ActionID")
sendEvent(obj.ActorSim, "ActionComplete", action.ActionID);
end
end
end
endActor Control Methods
setAttribute(actorSim, Pose=poseMatrix); % 4x4
setAttribute(actorSim, Velocity=[vx vy vz]); % 1x3
setAttribute(actorSim, AngularVelocity=[wx wy wz]); % 1x3
action = getAction(actorSim, "PathAction");
action = getAction(actorSim, "SpeedAction");
action = getAction(actorSim, "LaneChangeAction");
sendEvent(actorSim, "ActionComplete", actionID);
sendEvent(actorSim, "UserDefinedEvent", eventName, eventStruct);
eventData = receiveEvent(actorSim, "UserDefinedEvent", eventName);Workflow E: Co-Simulation with Simulink
Architecture
Create a Simulink model with the RoadRunner Scenario block at root level
Use RoadRunner Scenario Reader blocks to receive data from RoadRunner
Use RoadRunner Scenario Writer blocks to send data back
Publish the behavior:
Simulink.publish.publishActorBehavior("myModel", OutputFile="output.slprotodata")Assign the behavior to an actor (via RoadRunner UI, or programmatically in R2025a+ — see Workflow D)
Start simulation via
set_param("myModel", SimulationCommand="start")— NOTsim()
Key Constraints
The RoadRunner Scenario block must be at the model root level
Use
set_param(..., SimulationCommand="start")to start — neversim("model")Sample time in the RoadRunner Scenario block defines the co-sim step size (default 0.02s)
One MATLAB instance connects to one RoadRunner co-sim at a time
Bus types are loaded from
rrScenarioSimTypes.mat
Reader Topics
Actor Pose, Specifications, Lane Location, Vehicle Wheel Poses, Traffic Signals, Target Poses, Lane Boundaries, Actions (Path/Speed/Lane Change/etc.), User-Defined Events
Writer Topics
Actor Pose, Vehicle Pose, Action Complete, User-Defined Events, Diagnostics
See references/simulink-cosim-details.md for block configuration and bus types.
Workflow F: Observers (Read-Only Monitoring)
Observers monitor simulation state without modifying it. Unlike co-sim behaviors (assigned in UI), observers are added programmatically.
rrSim = createSimulation(rrApp);
addObserver(rrSim, "VelocityMonitor", "MyVelocityObserver");
simulateScenario(rrApp, IsBlocking=false);
% Observer's stepImpl is called each step automaticallyNote: The observer .m file must be on the MATLAB path. Use addpath if needed. Call addObserver BEFORE starting the simulation.
Observer System Object Pattern
classdef MyVelocityObserver < matlab.System
properties (Access = private)
ScenarioSim
end
methods (Access = protected)
function setupImpl(obj)
obj.ScenarioSim = Simulink.ScenarioSimulation.find( ...
"ScenarioSimulation");
end
function stepImpl(obj)
actors = get(obj.ScenarioSim, "ActorSimulation");
for idx = 1:numel(actors)
vel = getAttribute(actors{idx}, "Velocity");
% Read-only analysis — logging, visualization, etc.
end
end
end
endCRITICAL: Observers are READ-ONLY. They may call getAttribute but must NOT call setAttribute. They find the ScenarioSimulation (not ActorSimulation) in setupImpl.
Management:
addObserver(rrSim, name, fileName)— add (returns logical success)removeObserver(rrSim, name)— removeget(rrSim, "Observers")— query registered observers
Observers can also be Simulink models (.slx) since R2024b.
Workflow G: Sensor Simulation
Attach driving sensors to actors and read ground-truth data during simulation.
rrSim = createSimulation(rrApp);
sensorSim = get(rrSim, "SensorSimulation");
% Create and attach sensors to ego vehicle (actor ID 1)
visionSensor = visionDetectionGenerator(SensorIndex=1, ...
SensorLocation=[2.4 0], MaxRange=50);
radarSensor = drivingRadarDataGenerator(SensorIndex=2, ...
MountingLocation=[1.8 0 0.2]);
addSensors(sensorSim, {visionSensor, radarSensor}, 1);
% During step loop
set(rrSim, SimulationCommand="Start");
for i = 1:numSteps
set(rrSim, SimulationCommand="Step");
targets = targetPoses(sensorSim, 1); % struct array in ego frame
lanes = laneBoundaries(sensorSim, 1); % lane boundary data
end
set(rrSim, SimulationCommand="Stop");Key points:
SensorSimulationis obtained viaget(rrSim, "SensorSimulation")— NOT constructed directlyEach sensor must have a unique
SensorIndexThe second argument in
targetPoses(sensorSim, actorID)is the actorID of the ego vehicle (the one you attached sensors to viaaddSensors) — NOT the SensorIndextargetPosesreturns positions/velocities relative to the host vehiclelaneBoundariessupportsOutputOption:"EgoLane","EgoAdjacentLanes","AllLanes"
Supported sensors: visionDetectionGenerator, drivingRadarDataGenerator, ultrasonicDetectionGenerator, lidarPointCloudGenerator, lidarSensor
Scenario Variables
% Get a variable
value = getScenarioVariable(rrApp, "EgoSpeed");
% Set a variable (value MUST be a string)
setScenarioVariable(rrApp, "EgoSpeed", "30");
% Get all variables — returns struct ARRAY with Name/Value fields
allVars = getAllScenarioVariables(rrApp);
for i = 1:numel(allVars)
fprintf("%s = %s\n", allVars(i).Name, allVars(i).Value);
endDo NOT use fieldnames(allVars) — that gives struct field names (Name, Value), not variable names.
Simulation Log
Programmatic log access requires stepping mode or a completed simulation:
% After simulation completes (or during stepping)
simLog = get(rrSim, "SimulationLog");
% Query actor pose history — returns struct array with .Time and .Pose fields
poseLog = get(simLog, "Pose", "ActorID", 1);
% poseLog(i).Time — scalar timestamp
% poseLog(i).Pose — 4x4 transform matrix
% Extract positions for plotting
positions = arrayfun(@(s) s.Pose(1:3,4)', poseLog, UniformOutput=false);
positions = vertcat(positions{:}); % Nx3 matrix
% Save/load logs
save(rrSim, "SimulationLog", "myLog.mat");
log = load(rrSim, "SimulationLog", "myLog.mat");Log return format: get(simLog, "Pose", "ActorID", id) returns a struct array (not a numeric array). Each element has .Time (scalar) and .Pose (4x4 matrix). Use arrayfun to extract positions for plotting.
Key Functions
| Function | Purpose | Since |
|---|---|---|
simulateScenario(rrApp) | Run simulation to completion | R2024a |
createSimulation(rrApp) | Create ScenarioSimulation for step control | R2022a |
prepareSimulation(rrApp) | Submit sim data before co-sim clients connect | R2024a |
set(rrSim, SimulationCommand=cmd) | Control simulation | R2022a |
get(rrSim, param) | Query simulation state | R2022a |
addObserver(rrSim, name, file) | Add read-only observer | R2022a |
getAttribute(actorSim, attr) | Read actor runtime state | R2022a |
setAttribute(actorSim, NV) | Set actor state (co-sim only) | R2022a |
getAction(actorSim, name) | Get assigned action | R2022a |
sendEvent(actorSim, event, ...) | Send event to scenario | R2022b |
receiveEvent(actorSim, event, name) | Receive event from scenario | R2023a |
addSensors(sensorSim, sensors, actorID) | Attach sensors | R2023a |
targetPoses(sensorSim, sensorID) | Get target poses in ego frame | R2023a |
laneBoundaries(sensorSim, sensorID) | Get lane boundary data | R2023a |
Simulink.ScenarioSimulation.find(...) | Find active simulation/actors | R2022a |
Simulink.publish.publishActorBehavior(model) | Publish Simulink behavior | R2022a |
roadrunnerAPI(rrApp) | Get authoring API (Project, Scenario) | R2025a |
getAsset(prj, path, type) | Retrieve asset (BehaviorAsset, VehicleAsset, etc.) | R2025a |
createAsset(prj, path, type) | Create new asset in project | R2025a |
addActor(scnro, asset, position) | Add actor to scenario programmatically | R2025a |
See references/simulation-api-reference.md for full function signatures, name-value pairs, and return types.
Architecture: Actor Behavior Types
R2024a: Behaviors are assigned in the RoadRunner Scenario Editor UI only.
R2025a+: Behaviors can also be assigned programmatically via car.BehaviorAsset = behaviorAsset (see Workflow D).
| Behavior Type | What It Means | MATLAB Role |
|---|---|---|
| Ready-to-Run | Actor follows built-in path/logic | No code needed — just observe |
| MATLAB System | Actor controlled by a System object | Write System object (Workflow D) |
| Simulink Model | Actor controlled by Simulink model | Build model with RR blocks (Workflow E) |
Common Mistakes
| Mistake | Why It's Wrong | Correct Approach |
|---|---|---|
rrSim.start() / .step() / .stop() | Dot-method syntax does not exist | set(rrSim, SimulationCommand="Start"|"Step"|"Stop") |
actorSim.Pose or actorSim.Velocity | Not public properties | getAttribute(actorSim, "Pose") |
get(rrSim, "Actors") | Wrong parameter name | get(rrSim, "ActorSimulation") |
set(rrSim, Logging=true) | Value must be string | set(rrSim, Logging="On") |
Using drivingScenario for RoadRunner | Completely different toolbox | Use simulateScenario/createSimulation |
roadrunnerScenario(name) | This class does not exist | openScenario(rrApp, name) then simulate |
sim("model") for co-sim | Wrong command for co-simulation | set_param("model", SimulationCommand="start") |
setBehavior(actor, ...) | This function does not exist | Use car.BehaviorAsset = behaviorAsset (R2025a+) or assign in RoadRunner UI |
fieldnames(getAllScenarioVariables(rrApp)) | Gets struct fields, not variable names | allVars(i).Name |
log = simulateScenario(rrApp, ...) | No return value | Use createSimulation + get(rrSim, "SimulationLog") |
setAttribute in observer | Observers are read-only | Use getAttribute only |
addSensors(rrSim, ...) | Wrong object | addSensors(sensorSim, ...) on SensorSimulation |
getAttribute(actorSim, "Name") | Name is static, not runtime | get(actorSim, "ActorModel") then getAttribute(actorModel, "Name") |
actors(idx) after get(rrSim, "ActorSimulation") | Returns a cell array, not an object array | Use actors{idx} (cell indexing) |
set(rrSim, SimulationCommand="Start") then "Step" | "Start" runs freely — sim completes before you can step | Use simulateScenario(rrApp, IsSteppingStart=true, IsBlocking=false) first |
Step loop without pause(stepSize) | "Step" is async — commands pile up and are silently dropped | Add pause(stepSize) after each set(rrSim, SimulationCommand="Step") |
set(rrSim, Logging="On") during stepping | Errors "Failed to enable or disable logging while simulation is running" | Use simulateScenario(rrApp, ..., EnableLogging=true) before createSimulation |
Treating actors{1} as the ego vehicle | Index 1 is always the world actor (ID 0), not a vehicle | Use actors{2} or find by ID with Simulink.ScenarioSimulation.find("ActorSimulation", ActorID=uint64(id)) |
Simulink.ScenarioSimulation.find(..., ActorID=1) | ActorID must be uint64, not double | Use ActorID=uint64(1) |
createSimulation after simulateScenario in stepping mode | Server rejects connections while sim is paused | Call createSimulation(rrApp) BEFORE simulateScenario(rrApp, IsSteppingStart=true, ...) |
targetPoses(sensorSim, sensorIndex) | Second argument is the actorID, not sensorIndex | Use targetPoses(sensorSim, actorID) where actorID is the ego vehicle's ID |
setPlatform(behaviorAsset, "MATLAB") | Not a registered type string | Use setPlatform(behaviorAsset, "SimulinkPlatform") for both MATLAB and Simulink behaviors |
Conventions
Always use
set/getwith ScenarioSimulation — never dot-methodsAlways use
getAttribute/setAttributefor actor runtime stateUse
simulateScenariofor simple run-to-completion — don't over-engineer withcreateSimulationUse
createSimulationwhen you need step control, actor introspection, or log accessBehavior assignment: In R2024a, use RoadRunner UI. In R2025a+, use
car.BehaviorAsset = getAsset(prj, path, "BehaviorAsset")Co-sim System objects must use
Simulink.ScenarioSimulation.find("ActorSimulation", SystemObject=obj)insetupImplObservers find
"ScenarioSimulation"(not"ActorSimulation") and are read-onlyLifecycle: Opening a new scenario (
openScenario) invalidates any existingrrSim— callcreateSimulationagain
Copyright 2026 The MathWorks, Inc.
Files
- ATTRIBUTION.mdAdded by AutoGineer1.0 KiB
- LICENSELicence file added by AutoGineer1.4 KiB
- SKILL.md21.9 KiB
- manifest.yaml528 B
- references/simulation-api-reference.md6.5 KiB
- references/simulink-cosim-details.md3.2 KiB
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- MathWorks
- Publisher
- MathWorks (Official)
- Source
- matlab/matlab-agentic-toolkit · skills-catalog/automotive/roadrunner-scenario-simulating · commit 2a7f215
- Licence
- BSD 2-Clause License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by MathWorks.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download roadrunner-scenario-simulating.zip