mcpField
R
roadrunner-scenario-simulating

roadrunner-scenario-simulating

github.com/matlab其他1.2k46 次安装1 天前更新
代码仓库

关于 roadrunner-scenario-simulating

此 MATLAB 技能指导 RoadRunner 场景仿真的运行、逐步控制、协同仿真与结果读取,适合需要从 MATLAB 或 Simulink 操作场景的用户。内容涵盖演员状态、观察器、传感器和场景变量等工作流。

主要功能

  1. 01运行并逐步控制仿真
  2. 02通过 MATLAB 或 Simulink 控制演员
  3. 03监视仿真状态与演员属性
  4. 04附加传感器并读取目标数据
  5. 05访问仿真日志和场景变量

适用场景

  1. 01逐帧推进场景并读取仿真日志
  2. 02在协同仿真中控制车辆演员
  3. 03只读监视仿真状态
  4. 04获取传感器目标位姿或车道边界

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/matlab/matlab-agentic-toolkit --skill roadrunner-scenario-simulating

安装后在 Claude Code 中输入/roadrunner-scenario-simulating确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

manifest.yaml
references/
simulation-api-reference.md
simulink-cosim-details.md

详细介绍

RoadRunner 场景仿真

通过 MATLAB 和 Simulink 仿真 RoadRunner 场景、逐步执行仿真、在协同仿真中控制参与者、添加观察器、附加传感器并检索结果。

适用场景

  • 用户想要运行 RoadRunner 场景仿真
  • 用户想要逐帧执行仿真
  • 用户想要从外部控制参与者(协同仿真)
  • 用户想要观察仿真状态(只读监控)
  • 用户想要添加传感器并读取目标位姿或车道边界
  • 用户想要以编程方式检索仿真日志
  • 用户想要读取或写入场景变量
  • 用户询问与 Simulink 的协同仿真
  • 用户询问如何发布参与者行为

不适用场景

  • 启动或连接 RoadRunner
  • 编写场景(在编辑器中添加参与者、路径、行为)
  • 构建或编辑场景(道路、地形、资产)
  • 将参与者轨迹导出为 CSV — 请直接使用 exportActorTrajectoryToCSV
  • 使用 drivingScenario(这是另一个工具箱 — Automated Driving Toolbox)

重要:不要与 drivingScenario 混淆

drivingScenario(来自 Automated Driving Toolbox)是 MATLAB 原生的场景工具。 RoadRunner 场景仿真使用 roadrunner 对象上完全不同的 API。 切勿混用这两者 — 它们互不相关。


决策树

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)

工作流 A:简单仿真(运行至完成)

当用户只想仿真一个已打开的场景时使用:

openScenario(rrApp, "MyScenario");
simulateScenario(rrApp, EnableLogging=true);

选项:Pacing、IsBlocking、IsSteppingStart、EnableLogging。

重要: simulateScenario 不会返回日志对象。仅在只需运行至完成时使用它。如果需要在 MATLAB 中以编程方式访问仿真日志,请改用 createSimulation(工作流 B)。


工作流 B:逐步仿真

当用户需要逐帧控制或以编程方式访问日志时使用。

**关键调用顺序:**必须先调用 createSimulation,然后才能调用 simulateScenario。仿真正在运行或暂停时,Scenario Server 会拒绝新连接。此外,不要使用 set(rrSim, SimulationCommand="Start") 然后再使用 "Step" — "Start" 会让仿真自由运行直至完成。

% 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");

关键:"Step" 是异步的 — 每次 Step 之后都必须添加 pause(stepSize)。否则,命令会堆积并被静默丢弃。不要使用点方法语法(rrSim.step())— 始终使用 set(rrSim, SimulationCommand=...)。逐步执行时不要设置 Logging="On" — 请在 simulateScenario 调用中使用 EnableLogging=true。

SimulationCommand 的取值

"Start"、"Step"、"Pause"、"Continue"、"Stop"、"Replay"

Replay 使用位置语法:set(rrSim, "SimulationCommand", "Replay", fileName)

轮询 SimulationStatus

get(rrSim, "SimulationStatus") 返回:"Inactive"、"Running"、"Paused"、"Done"

运行非阻塞仿真时,在等待循环中使用。如果轮询未能及时捕获状态,短场景可能会在轮询检查到 "Done" 之前就已转为其他状态,因此请同时检查 "Done" 和 "Inactive":

status = get(rrSim, "SimulationStatus");
while ~ismember(status, ["Done", "Inactive"])
    pause(0.1);
    status = get(rrSim, "SimulationStatus");
end

工作流 C:读取参与者状态

在逐步仿真过程中获取参与者信息:

注意:get(rrSim, "ActorSimulation") 始终会在索引 1 处包含世界参与者(ID 0)。这是一个不可移动的根参与者,不是车辆。遍历时请跳过它,或按 ID 进行筛选。

**注意:**只有仿真处于活动状态(Running 或 Paused)时,才能查询参与者。"Stop" 之后,get(rrSim, "ActorSimulation") 会返回空值。

% 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 vector

**关键:**不要使用 actorSim.Pose 或 actorSim.Velocity — 它们不是公共属性。始终使用 getAttribute(actorSim, "AttrName")。

运行时属性:"ID"、"Pose"、"Velocity"、"AngularVelocity"、"WheelPoses"、"LaneLocation"、"Children"、"Parent"、"PhaseStatus"、"ActorType"、"TrafficSignalRuntime"、"TrafficSignalControllerRuntime"

静态属性(名称、边界框等)

要获取 Actor 的名称或其他静态属性,请使用 ActorModel,而不是 getAttribute(actorSim, "Name")(该函数不存在):

actorModel = get(actorSim, "ActorModel");
actorName = getAttribute(actorModel, "Name");
boundingBox = getAttribute(actorModel, "BoundingBox");

ActorModel 上的静态属性:"ID"、"Name"、"PaintColor"、"BoundingBox"、"WheelSpec"、"TrafficSignalSpec"、"TrafficSignalControllerSpec"


工作流 D:使用 MATLAB System 对象进行协同仿真

架构
  1. 为 Actor 分配行为(见下文)
  2. 在 MATLAB 中:编写一个在运行时控制 Actor 的 System 对象
  3. System 对象通过 Simulink.ScenarioSimulation.find 查找自身
分配行为

R2024a: 只能在 RoadRunner Scenario Editor UI 中分配行为(没有 MATLAB API)。

R2025a+: 可通过 roadrunnerAPI 创作接口以编程方式分配行为:

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;

要点:

  • roadrunnerAPI(rrApp) 可访问 Project 和 Scenario 对象
  • 使用 getAsset(prj, path, "BehaviorAsset") 获取现有的 .rrbehavior 资源
  • 使用 createAsset(prj, path, "BehaviorAsset") 创建新的行为资源
  • 创建行为资源后,设置其平台:setPlatform(behaviorAsset, "SimulinkPlatform")——这对 MATLAB System 对象和 Simulink 模型都适用。不要使用 "MATLAB"、"External" 或 "MATLABSystem"(这些平台未注册)
  • 通过 Vehicle/Character/MovableObject 上的 BehaviorAsset 属性进行分配
  • 不存在 setBehavior() 函数——请改用属性赋值
System 对象模式
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
end
Actor 控制方法
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);

工作流 E:使用 Simulink 进行协同仿真

架构
  1. 在根级别创建一个包含 RoadRunner Scenario 模块的 Simulink 模型
  2. 使用 RoadRunner Scenario Reader 模块接收来自 RoadRunner 的数据
  3. 使用 RoadRunner Scenario Writer 模块将数据发送回 RoadRunner
  4. 发布行为:Simulink.publish.publishActorBehavior("myModel", OutputFile="output.slprotodata")
  5. 将行为分配给 Actor(通过 RoadRunner UI,或在 R2025a+ 中以编程方式分配——见工作流 D)
  6. 通过 set_param("myModel", SimulationCommand="start") 启动仿真——不要使用 sim()
关键限制
  • RoadRunner Scenario 模块必须位于模型根级别
  • 使用 set_param(..., SimulationCommand="start") 启动——绝不要使用 sim("model")
  • RoadRunner Scenario 模块中的采样时间定义协同仿真的步长(默认为 0.02s)
  • 一个 MATLAB 实例一次只能连接一个 RoadRunner 协同仿真
  • 总线类型从 rrScenarioSimTypes.mat 加载
读取器主题

Actor 位姿、规格、车道位置、车辆车轮位姿、交通信号、目标位姿、车道边界、动作(路径/速度/变道等)、用户定义事件

写入器主题

Actor 位姿、车辆位姿、动作完成、用户定义事件、诊断信息

模块配置和总线类型请参见 references/simulink-cosim-details.md。


工作流 F:观察器(只读监控)

观察器监控仿真状态,但不会对其进行修改。与协同仿真行为(在 UI 中分配)不同,观察器以编程方式添加。

rrSim = createSimulation(rrApp);
addObserver(rrSim, "VelocityMonitor", "MyVelocityObserver");
simulateScenario(rrApp, IsBlocking=false);
% Observer's stepImpl is called each step automatically

注意: 观察器 .m 文件必须位于 MATLAB 路径中。如有需要,请使用 addpath。必须在启动仿真之前调用 addObserver。

观察器 System 对象模式
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
end

重要: 观察器是只读的。它们可以调用 getAttribute,但不得调用 setAttribute。它们在 setupImpl 中查找 ScenarioSimulation(而非 ActorSimulation)。

管理:

  • addObserver(rrSim, name, fileName) — 添加观察器(返回逻辑成功状态)
  • removeObserver(rrSim, name) — 移除观察器
  • get(rrSim, "Observers") — 查询已注册的观察器

自 R2024b 起,观察器也可以是 Simulink 模型(.slx)。

工作流 G:传感器仿真

将驾驶传感器附加到参与者,并在仿真期间读取真实值数据。

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");

要点:

  • SensorSimulation 通过 get(rrSim, "SensorSimulation") 获取——不能直接构造
  • 每个传感器都必须有唯一的 SensorIndex
  • targetPoses(sensorSim, actorID) 的第二个参数是自车(即通过 addSensors 附加传感器的车辆)的 actorID,不是 SensorIndex
  • targetPoses 返回相对于宿主车辆的位置/速度
  • laneBoundaries 支持 OutputOption:"EgoLane"、"EgoAdjacentLanes"、"AllLanes"

支持的传感器:visionDetectionGenerator、drivingRadarDataGenerator、ultrasonicDetectionGenerator、lidarPointCloudGenerator、lidarSensor


场景变量

% 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);
end

不要使用 fieldnames(allVars)——它返回的是结构体字段名(Name、Value),而不是变量名。


仿真日志

以编程方式访问日志需要处于步进模式或仿真已完成:

% 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");

日志返回格式:get(simLog, "Pose", "ActorID", id) 返回一个结构体数组(不是数值数组)。每个元素都有 .Time(标量)和 .Pose(4x4 矩阵)。使用 arrayfun 提取位置以进行绘图。


关键函数

函数用途起始版本
simulateScenario(rrApp)运行仿真直至完成R2024a
createSimulation(rrApp)创建用于步进控制的 ScenarioSimulationR2022a
prepareSimulation(rrApp)在协同仿真客户端连接前提交仿真数据R2024a
set(rrSim, SimulationCommand=cmd)控制仿真R2022a
get(rrSim, param)查询仿真状态R2022a
addObserver(rrSim, name, file)添加只读观察器R2022a
getAttribute(actorSim, attr)读取参与者运行时状态R2022a
setAttribute(actorSim, NV)设置参与者状态(仅限协同仿真)R2022a
getAction(actorSim, name)获取已分配的动作R2022a
sendEvent(actorSim, event, ...)向场景发送事件R2022b
receiveEvent(actorSim, event, name)接收来自场景的事件R2023a
addSensors(sensorSim, sensors, actorID)附加传感器R2023a
targetPoses(sensorSim, sensorID)获取自车坐标系中的目标姿态R2023a
laneBoundaries(sensorSim, sensorID)获取车道边界数据R2023a
Simulink.ScenarioSimulation.find(...)查找活动仿真/参与者R2022a
Simulink.publish.publishActorBehavior(model)发布 Simulink 行为R2022a
roadrunnerAPI(rrApp)获取创作 API(Project、Scenario)R2025a
getAsset(prj, path, type)获取资源(BehaviorAsset、VehicleAsset 等)R2025a
createAsset(prj, path, type)在项目中创建新资源R2025a
addActor(scnro, asset, position)以编程方式向场景添加参与者R2025a

完整的函数签名、名称-值对和返回类型,请参阅 references/simulation-api-reference.md。


架构:参与者行为类型

**R2024a:**只能在 RoadRunner Scenario Editor UI 中分配行为。 **R2025a+:**也可以通过 car.BehaviorAsset = behaviorAsset 以编程方式分配行为(参见工作流 D)。

行为类型含义MATLAB 中的职责
Ready-to-Run参与者遵循内置路径/逻辑无需编写代码——只需观察
MATLAB System参与者由 System 对象控制编写 System 对象(工作流 D)
Simulink Model参与者由 Simulink 模型控制使用 RR 模块构建模型(工作流 E)

常见错误

错误错误原因正确做法
rrSim.start() / .step() / .stop()不存在点方法语法set(rrSim, SimulationCommand="Start"|"Step"|"Stop")
actorSim.Pose 或 actorSim.Velocity不是公共属性getAttribute(actorSim, "Pose")
get(rrSim, "Actors")参数名称错误get(rrSim, "ActorSimulation")
set(rrSim, Logging=true)值必须是字符串set(rrSim, Logging="On")
将 drivingScenario 用于 RoadRunner它属于完全不同的工具箱使用 simulateScenario/createSimulation
roadrunnerScenario(name)此类不存在先调用 openScenario(rrApp, name),再进行仿真
使用 sim("model") 进行协同仿真协同仿真的命令错误set_param("model", SimulationCommand="start")
setBehavior(actor, ...)此函数不存在使用 car.BehaviorAsset = behaviorAsset(R2025a+),或在 RoadRunner UI 中分配
fieldnames(getAllScenarioVariables(rrApp))获取的是结构体字段,而不是变量名称allVars(i).Name
log = simulateScenario(rrApp, ...)没有返回值使用 createSimulation + get(rrSim, "SimulationLog")
在观察器中使用 setAttribute观察器为只读只能使用 getAttribute
addSensors(rrSim, ...)对象错误在 SensorSimulation 上使用 addSensors(sensorSim, ...)
getAttribute(actorSim, "Name")Name 是静态属性,不是运行时属性使用 get(actorSim, "ActorModel"),然后使用 getAttribute(actorModel, "Name")
在调用 get(rrSim, "ActorSimulation") 后使用 actors(idx)返回的是元胞数组,而不是对象数组使用 actors{idx}(元胞索引)
先调用 set(rrSim, SimulationCommand="Start"),再调用 "Step""Start" 会自由运行——仿真会在你能执行步进之前完成先使用 simulateScenario(rrApp, IsSteppingStart=true, IsBlocking=false)
不带 pause(stepSize) 的步进循环"Step" 是异步的——命令会堆积并被静默丢弃在每次 set(rrSim, SimulationCommand="Step") 后添加 pause(stepSize)
步进期间调用 set(rrSim, Logging="On")会报错 "Failed to enable or disable logging while simulation is running"在调用 createSimulation 之前,使用 simulateScenario(rrApp, ..., EnableLogging=true)
将 actors{1} 视为自车索引 1 始终是世界 Actor(ID 0),而不是车辆使用 actors{2},或通过 ID 查找:Simulink.ScenarioSimulation.find("ActorSimulation", ActorID=uint64(id))
Simulink.ScenarioSimulation.find(..., ActorID=1)ActorID 必须是 uint64,而不是 double使用 ActorID=uint64(1)
在步进模式下,调用 simulateScenario 后再调用 createSimulation仿真暂停时,服务端会拒绝连接在调用 simulateScenario(rrApp, IsSteppingStart=true, ...) 之前调用 createSimulation(rrApp)
targetPoses(sensorSim, sensorIndex)第二个参数是 actorID,而不是 sensorIndex使用 targetPoses(sensorSim, actorID),其中 actorID 是自车的 ID
setPlatform(behaviorAsset, "MATLAB")不是已注册的类型字符串MATLAB 和 Simulink 行为都使用 setPlatform(behaviorAsset, "SimulinkPlatform")

约定

  • 使用 ScenarioSimulation 时,始终使用 set/get,切勿使用点方法
  • 对于 Actor 运行时状态,始终使用 getAttribute/setAttribute
  • 对于简单的运行至完成场景,使用 simulateScenario;不要用 createSimulation 过度设计
  • 需要控制步进、检查 Actor 或访问日志时,使用 createSimulation
  • 行为分配: 在 R2024a 中,使用 RoadRunner 界面。在 R2025a+ 中,使用 car.BehaviorAsset = getAsset(prj, path, "BehaviorAsset")
  • 协同仿真系统对象必须在 setupImpl 中使用 Simulink.ScenarioSimulation.find("ActorSimulation", SystemObject=obj)
  • 观察器查找 "ScenarioSimulation"(而非 "ActorSimulation"),且为只读
  • 生命周期: 打开新场景(openScenario)会使任何现有的 rrSim 失效;请再次调用 createSimulation

Copyright 2026 The MathWorks, Inc.

评论

支持 Markdown