Matlab Cosimulate Sumo Simulink
MathWorksOfficialCreated by MathWorks
- Skill
- Tool integration
- Software development
- BSD-2-Clause
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to building Simulink models that perform synchronized co-simulation with the Eclipse SUMO traffic simulator. It covers the configuration of Server and Client blocks, managing vehicle states, dynamic traffic generation, and ego vehicle control. The guide emphasizes robust model construction, including handling simulation timing, managing vehicle lifecycles through gated subsystems, and implementing visualization commands, ensuring reliable communication between the Simulink controller and the SUMO environment.
What it does
- Configures Server and Client blocks to establish a TraCI connection between Simulink and SUMO.
- Provides patterns for spawning and removing vehicles dynamically during a simulation.
- Enables reading vehicle states like position and speed from SUMO into Simulink.
- Supports longitudinal control of ego vehicles from Simulink controllers.
- Includes methods for generating random background traffic without manual route files.
- Offers guidance on managing SUMO GUI visualization settings via Simulink writers.
When to use it
- When you need to perform ADAS or autonomous driving controller testing in a traffic environment.
- When you want to connect a Simulink model to an external traffic simulator like SUMO.
- When you need to implement vehicle-in-the-loop testing scenarios.
- When you need to validate traffic scenarios using SUMO's network and route files.
Advantages
- Enables high-fidelity co-simulation between control logic and traffic environments.
- Supports dynamic vehicle management for complex traffic scenarios.
- Provides clear patterns for handling simulation timing and synchronization.
- Includes workarounds for common integration issues like Windows path separators and block crashes.
Usage examples
- “How do I connect my Simulink model to a running SUMO simulation?”
- You must add a Server block configured with your .sumocfg file and a Client block with matching port numbers, ensuring both use a fixed-step solver that matches the SUMO step-length.
- “My simulation crashes when I try to read vehicle data. Why?”
- The Reader block likely attempts to access a vehicle that does not exist yet. You must gate the Reader inside an Enabled Subsystem that only activates once the vehicle has spawned.
- “How can I spawn a vehicle at a specific position in SUMO from Simulink?”
- Use an Actor block to add the vehicle to a lane, then use a Writer block to teleport it to the desired coordinates, ensuring a one-step delay between the spawn and the move command.
- “How do I change the SUMO GUI view to 'real world' mode during simulation?”
- Use a Writer block with TopicCategory set to Visualization and GUITopic set to Schema, wrapped in a one-shot Enabled Subsystem to ensure the command is sent only once.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/matlab/matlab-cosimulate-sumo-simulink/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip matlab-cosimulate-sumo-simulink.zip -d .agents/skills
Documentation by MathWorks
Build SUMO-Simulink Co-simulation
Create Simulink models that run synchronized co-simulation with Eclipse SUMO using the SumoInterfaceLibrary blocks from the Automated Driving Toolbox Interface for Eclipse SUMO Traffic Simulator.
When to Use
Building a Simulink model that connects to Eclipse SUMO
Setting up traffic co-simulation for ADAS/AD controller testing
Reading vehicle states (position, speed) from SUMO into Simulink
Controlling an ego vehicle in SUMO from a Simulink controller
Spawning or removing vehicles dynamically during simulation
Generating random background traffic without writing route files
When NOT to Use
Pure SUMO simulation without Simulink (use SUMO's CLI or Python TraCI directly)
Vehicle dynamics modeling (use Vehicle Dynamics Blockset)
Scenario design with Driving Scenario Designer (different workflow)
Prerequisites
Eclipse SUMO installed with
SUMO_HOMEenvironment variable setSupport package installed: "Automated Driving Toolbox Interface for Eclipse SUMO Traffic Simulator"
Windows: append trailing separator to
SUMO_HOME— The Server block's launcher concatenatesSUMO_HOME + "bin\..."without a separator. IfSUMO_HOMElacks a trailing\or/, everysim()fails with "Failed to launch Eclipse SUMO simulator" even though SUMO is installed correctly. Always run before building/simulating:
if ~endsWith(getenv('SUMO_HOME'), filesep)
setenv('SUMO_HOME', [getenv('SUMO_HOME') filesep]);
endVerify:
getenv('SUMO_HOME')must return a valid path ending with a separator.
Preferred Construction Path
When mcp__matlab__model_edit (SATK) is available, prefer it over raw add_block/add_line. It applies auto-layout after every edit, produces clean wiring with no overlap, and lets you reference newly-added blocks by ref within the same call. The patterns below still apply — express them as add_block/connect/configure operations in a single JSON payload. Fall back to add_block/add_line only when SATK is unavailable or when the operation is not expressible in the schema (e.g., setting MATLAB Function Script via sfroot).
Note: When wiring EnablePort on a freshly-created Enabled Subsystem whose default In1/Out1 have been deleted, model_edit cannot resolve the Enable port. Workaround: add_line(model, 'Source/1', 'SubsystemName/Enable', 'autorouting','smart').
Workflow
Idempotent Build Template
modelName = 'sumo_cosim';
workDir = fileparts(mfilename('fullpath'));
% SUMO_HOME workaround (Windows)
sh = getenv('SUMO_HOME');
if ~endsWith(sh, filesep), setenv('SUMO_HOME', [sh filesep]); end
% Idempotent rebuild
if bdIsLoaded(modelName), close_system(modelName, 0); end
slxPath = fullfile(workDir, [modelName '.slx']);
if isfile(slxPath), delete(slxPath); end
new_system(modelName);
open_system(modelName);
set_param(modelName, 'StopTime','100', 'SolverType','Fixed-step', 'FixedStep','0.1');
% ... build model ...
save_system(modelName, slxPath);1. Prepare SUMO Scenario Files
Ask the user for their existing .sumocfg. Only generate new files if explicitly requested. For quick networks use netgenerate:
sumoHome = getenv('SUMO_HOME');
cmd = sprintf('"%s" --grid --grid.number 2 --grid.length 200 --output-file "%s"', ...
fullfile(sumoHome,'bin','netgenerate'), fullfile(pwd,'network.net.xml'));
system(cmd);Minimal .sumocfg (route-files optional when using EnableRandomTraffic):
<configuration>
<input><net-file value="network.net.xml"/></input>
<time><begin value="0"/><end value="100"/><step-length value="0.1"/></time>
</configuration>Route file rules: All <vehicle>, <person>, and <personFlow> entries MUST be sorted by depart time (begin for flows). Out-of-order entries are silently ignored. Routes used by Actor blocks must be standalone <route> elements — not embedded in <flow>.
OpenDRIVE import: Use netconvert --opendrive-files file.xodr -o network.net.xml. Note: SUMO applies a netOffset (visible in .net.xml <location> element) — all SUMO coordinates = OpenDRIVE coordinates + netOffset.
2. Create Server and Client
add_block('SumoInterfaceLibrary/Server', [modelName '/SUMO Server']);
set_param([modelName '/SUMO Server'], 'ServerFile',fullfile(pwd,'cosim.sumocfg'), ...
'ServerPort','8813', 'ServerNumClients','1', 'EnablePacing','on', ...
'PacingRate','1', 'SampleTime','0.1');
add_block('SumoInterfaceLibrary/Client', [modelName '/SUMO Client']);
set_param([modelName '/SUMO Client'], 'ClientAddress','127.0.0.1', ...
'ClientPort','8813', 'ClientOrder','1', 'SampleTime','0.1');Critical: ClientPort must equal ServerPort. FixedStep must match SUMO step-length. Enable pacing (EnablePacing='on') so the GUI doesn't flash by in 2 seconds.
3–6. Add Readers, Writers, Actors, Save and Run
See Block Reference and Patterns sections below. Always save_system(modelName) before sim(modelName) when the model has been modified programmatically.
Block Reference
Server Block
| Parameter | Purpose | Default |
|---|---|---|
ServerFile | Path to .sumocfg | — |
ServerPort | TraCI port | '8813' |
ServerNumClients | Number of clients | '1' |
EnableRandomTraffic | Spawn vehicles without route file | 'off' |
RandomTraffic | Vehicle count when random traffic enabled | '0' |
EnablePacing | Real-time pacing (recommended for demos) | 'off' |
PacingRate | Pacing multiplier | '1' |
SampleTime | Step interval | '-1' |
Note: SUMO default time-to-teleport=300s — any vehicle stuck >300s gets teleported. This can surprise when deliberately stopping an ego at a bus stop.
Client Block
| Parameter | Purpose | Default |
|---|---|---|
ClientAddress | Server IP | '127.0.0.1' |
ClientPort | Must match ServerPort | '8813' |
ClientOrder | Client priority | '1' |
Reader Block — Vehicle Topics
All Vehicle-topic Readers AND Writers crash if the target vehicle does not exist. Gate them in Enabled Subsystems when the vehicle spawns after t=0. See Safe Vehicle State Access.
| Topic | Input | Output |
|---|---|---|
Speed | Vehicle Id | Speed (scalar) |
Position | Vehicle Id | Position [x, y] |
Position3D | Vehicle Id | Position [x, y, z] |
Acceleration | Vehicle Id | Acceleration |
Angle | Vehicle Id | Heading (degrees, 0=north, CW) |
Vehicle Id inputs must come from a String Constant block — never from another Reader's output.
Reader Block — Simulation Topics (no input port)
| Topic | Output |
|---|---|
ID list | Vehicle ID strings |
ID count | Scalar count |
Arrived list | IDs that reached destination |
Departed list | IDs that entered network |
Writer Block — Vehicle Topics
Writers crash if the target vehicle does not exist — same failure mode as Readers. Gate in Enabled Subsystems for delayed-spawn vehicles.
| Topic | Input Ports | Notes |
|---|---|---|
Speed | Vehicle Id, Speed | Sets desired speed; SUMO car-following still brakes for leaders |
Position (RouteFlag off) | Vehicle Id, X, Y, Angle | — |
Position (RouteFlag on) | Vehicle Id, Edge Id, Lane Index, X, Y, Angle, Keep Route | See type table below |
Min gap | Vehicle Id, Gap | — |
Speed mode | Vehicle Id, Mode | — |
Writer(Vehicle/Position, RouteFlag=on) port types — type mismatches silently fail:
| Port | Signal | Type |
|---|---|---|
| 1 | Vehicle Id | string |
| 2 | Edge Id | string |
| 3 | Lane Index | int32 |
| 4 | X | double |
| 5 | Y | double |
| 6 | Angle | double (degrees) |
| 7 | Keep Route | uint8 (use uint8(1)) |
Warning: Writer(Vehicle/Position) does no collision-checking. Teleporting near other vehicles causes pile-ups. Place spawned vehicles in a different lane from nearby traffic.
Writer Block — Visualization Topics
Use TopicCategory='Visualization' with GUITopic parameter. Visualization commands are sticky — once SUMO receives Schema/Track/Zoom, it retains the setting. Always wrap in a one-shot Enabled Subsystem. Do NOT leave running every step.
| GUITopic | Input Ports | Valid Values |
|---|---|---|
Track Vehicle | View Id, Vehicle Id | — |
Zoom factor | View Id, Zoom | — |
Schema | View Id, Schema | "standard", "real world", "fast standard", "fast real world" |
All Visualization topics require a View Id input on port 1. The default SUMO GUI view name is "View #0" — always use this exact string.
% Track Vehicle example (one-shot): camera follows ego
add_block('SumoInterfaceLibrary/Writer', [subsysPath '/Track Writer'], ...
'TopicCategory','Visualization', 'GUITopic','Track Vehicle', 'SampleTime','0.1');
add_block('simulink/String/String Constant', [subsysPath '/View Id'], ...
'String','"View #0"'); % Default SUMO GUI view — always "View #0"
add_block('simulink/String/String Constant', [subsysPath '/Vehicle Id'], ...
'String','"ego_vehicle"');
add_line(subsysPath, 'View Id/1', 'Track Writer/1');
add_line(subsysPath, 'Vehicle Id/1', 'Track Writer/2');
% Wrap in one-shot Enabled Subsystem (Constant(0)->IC(1)->Enable)% Schema example (one-shot): switch GUI to "real world"
add_block('SumoInterfaceLibrary/Writer', [modelName '/Set Schema'], ...
'TopicCategory','Visualization', 'GUITopic','Schema', 'SampleTime','0.1');
add_block('simulink/String/String Constant', [modelName '/View Id'], ...
'String','"View #0"'); % Default SUMO GUI view — always "View #0"
add_block('simulink/String/String Constant', [modelName '/Schema Name'], ...
'String','"real world"');
% Wrap in one-shot Enabled Subsystem (Constant(0)->IC(1)->Enable)Actor Block
| Parameter | Purpose |
|---|---|
VehicleState | 'Add' or 'Remove' |
SpawnMethod | 'Lane' (use this) or 'Position' (broken — see Known Issues) |
departLane | 'random', 'free', 'allowed', 'first', 'best' |
departSpeed | 'max' (recommended), 'random', 'desired', 'speedLimit' |
enableRouteID | 'on'/'off' |
routeID | Route ID from .rou.xml (requires enableRouteID='on') |
typeID | Vehicle type ID (default: 'DEFAULT_VEHTYPE') |
Always place Actor blocks inside Enabled Subsystems. Set Priority='1' on Spawn subsystem so it executes before Readers (Priority='10').
Patterns
Single-Shot Triggers
| Trigger | Pattern |
|---|---|
| Spawn at t=0 only | Constant(0) -> IC(Value=1) -> Enabled Subsystem |
| Spawn at simulation time T | Clock -> MATLAB Function (persistent fired) -> Enabled Subsystem |
| Continuous from T onward (e.g., speed writer) | Clock -> Compare To Constant (>=T) -> Enabled Subsystem |
| Spawn when condition true | Clock/sensor -> MATLAB Function (persistent fired) checking condition |
Time-based one-shot (spawn at t=1.2):
% MATLAB Function code:
% function pulse = fcn(t)
% %#codegen
% persistent fired
% if isempty(fired), fired = false; end
% if (t >= 1.2) && ~fired, pulse = 1.0; fired = true;
% else, pulse = 0.0; end
% endEgo Vehicle Control (Route-File Approach — Recommended)
Define ego in .rou.xml with depart="0" so Readers work from t=0:
<routes>
<vType id="ego_type" accel="2.6" decel="4.5" sigma="0" length="5" maxSpeed="25"/>
<route id="ego_route" edges="B1B2 B2B3 B3B4 B4B1 B1B2 B2B3 B3B4 B4B1"/>
<vehicle id="ego_veh" type="ego_type" route="ego_route" depart="0"
departLane="free" departSpeed="max"/>
</routes>If Simulink owns longitudinal control via Writer(Vehicle/Speed), do NOT put <stop> clauses in the ego's route — SUMO's stop directive overrides the Speed Writer.
Gated Writer(Vehicle/Speed) for Delayed-Spawn Vehicles
% Latched enable: HIGH from t >= spawnTime onwards
% Clock -> Compare To Constant (relop='>=', const=spawnTime) -> Enable
% Inside Enabled Subsystem:
% String Constant("veh_1") -> Writer(Vehicle/Speed) port 1
% Constant(desiredSpeed) -> Writer(Vehicle/Speed) port 2Use Compare To Constant >= spawnTime (stays HIGH) rather than one-shot — speed must be continuously asserted while the vehicle is alive.
Distinct Routes Per Vehicle (Dynamic Spawning)
<routes>
<route id="ego_route" edges="A0A1 A1A2 A2B2 B2C2 C2C1 C1C0"/>
<route id="veh_1_route" edges="A1B1 B1B2 B2C2 C2C1 C1C0 C0B0"/>
<route id="veh_2_route" edges="B0B1 B1A1 A1A2 A2B2 B2C2 C2C1"/>
</routes>% Per Actor block: set_param(actorPath, 'routeID', sprintf('veh_%d_route', k));Spawn-Then-Teleport (Position Workaround)
Since SpawnMethod='Position' is broken (see Known Issues), use this two-step pattern:
Step N: Actor(Add, SpawnMethod='Lane', routeID=...) -> vehicle at edge start
Step N+1: Writer(Vehicle/Position, RouteFlag=on) with (VehId, EdgeId, int32(LaneIdx),
X, Y, Angle, uint8(1)) -> vehicle teleports to (X,Y)A one-step delay between Spawn and Move is mandatory — use a Unit Delay on the enable signal. The vehicle does not exist on the SUMO side until one step after the Actor fires.
Periodic Batch Spawn Near Moving Reference
Clock -> PulseGen (persistent, fires every 5s, increments batch id)
-> SpawnBatch (Enabled SS, Priority=1): N IDGen -> N Actor(Add)
-> [Unit Delay z^-1]
-> MoveBatch (Enabled SS, Priority=10): N Writer(Vehicle/Position)
Reader(Vehicle/Position) on ego feeds PosGen so batch lands at egoPos + offset.MATLAB Function with String Outputs
For dynamically generated vehicle IDs (e.g., "dyn_" + string(batch) + "_1"):
chart = sf.find('-isa','Stateflow.EMChart','Path',chartPath);
chart.ChartUpdate = 'DISCRETE';
chart.SampleTime = '0.1';
outData = chart.find('-isa','Stateflow.Data','Scope','Output');
outData.DataType = 'string';
outData.Props.Array.Size = '1';Safe Vehicle State Access
All Vehicle-topic Readers AND Writers dereference the Vehicle Id at every step. They crash if the vehicle does not exist. This applies to Reader(Vehicle/...), Writer(Vehicle/...), AND Writer(Visualization/Track Vehicle).
For vehicles spawning after t=0, gate in an Enabled Subsystem:
% Clock -> Compare To Constant (>= spawnTime) -> Enabled Subsystem
% Inside: String Constant + Reader/Writer blocksFor ego defined in .rou.xml with depart="0" — no gating needed.
Random Traffic Quick-Start
set_param([modelName '/SUMO Server'], 'EnableRandomTraffic','on', 'RandomTraffic','10');No <route-files> needed. Random vehicles are named SpawnedVehicle_1, SpawnedVehicle_2, etc.
Known Issues (Support Package Bugs)
| Issue | Impact | Workaround |
|---|---|---|
SUMO_HOME without trailing separator → launch failure (Windows) | P0 blocker | setenv('SUMO_HOME', [getenv('SUMO_HOME') filesep]) |
SpawnMethod='Position' passes wrong RouteFlag in internal moveToXY | Vehicle lands at edge start, not requested position | Use spawn-then-teleport pattern (Actor + Unit Delay + Writer(Vehicle/Position)) |
Common Mistakes
| Mistake | Why It Fails | Fix |
|---|---|---|
| Reader/Writer on vehicle before it exists | S-function crash in mdlOutputs | Gate in Enabled Subsystem; use depart="0" for ego |
| Reader output -> Reader input | ID List is variable-length; Vehicle readers need single string | Use String Constant for Vehicle Id |
| ClientPort != ServerPort | Client can't connect | Match both (default '8813') |
| Variable-step solver | SUMO requires lockstep | Fixed-step, match step-length |
| Actor fires repeatedly | "Vehicle already exists" | Enabled Subsystem with one-shot logic |
| Writer(Vehicle/Speed) ungated for delayed-spawn vehicle | Crash at t=0 | Gate with Clock >= spawnTime |
| Visualization Writer running every step | Wastes sim time; crashes if vehicle missing | One-shot Enabled Subsystem |
| Route entries not sorted by depart time | Silently dropped | Sort all entries by depart/begin |
Route embedded in <flow> | Actor can't find it | Define standalone <route> elements |
<stop> in ego route + Speed Writer | SUMO stop overrides Writer | Remove <stop>; use Simulink speed profile |
| Multiple Clock blocks | Clutter; all output same time | Single Clock, fan out to all consumers |
double for Lane Index or Keep Route in Position Writer | Type mismatch rejection | int32(laneIdx), uint8(keepRoute) |
| Teleport into occupied lane | Pile-ups, stuck vehicles | Teleport to different lane from nearby traffic |
Missing save_system before sim | "Unapplied changes" mask error | Always save after programmatic changes |
Ego depart="2" with Reader at t=0 | Garbage/crash from undefined vehicle | Set ego depart="0" |
| Spawning at fractional times with FixedStep=1.0 | Solver never hits target time | Match FixedStep, step-length, and all SampleTime |
Conventions
Always use Fixed-step solver with step size matching SUMO
step-lengthand all blockSampleTimevaluesAlways
save_system(modelName)beforesim(modelName)after programmatic changesAlways match
ClientPorttoServerPortUse a single Clock at model root — fan out to all comparators/pulse generators
Prefer defining ego in
.rou.xmlwithdepart="0"over Actor blockGive ego a long/circular route to prevent mid-simulation removal
Use
departSpeed='max'as the practical default for vehicles that should land movingWriter(Speed) sets desired speed — SUMO handles gap maintenance via car-following
Enable pacing (
EnablePacing='on') for demos so the GUI doesn't flash byWrap Visualization writers (Track, Schema, Zoom) in one-shot Enabled Subsystems — they are sticky
Always place Actor blocks inside Enabled/Triggered Subsystems
Every dynamically spawned vehicle needs a unique ID and a valid standalone route
Validate
.sumocfgwith SUMO CLI before Simulink:system(sprintf('"%s" -c "%s" --end 0.1', sumoExe, cfgFile))When using
mcp__matlab__model_edit, fall back toadd_linefor Enable port wiring
Copyright 2026 The MathWorks, Inc.
Files
- ATTRIBUTION.mdAdded by AutoGineer1.0 KiB
- LICENSELicence file added by AutoGineer1.4 KiB
- SKILL.md18.7 KiB
- manifest.yaml528 B
LICENSE
Copyright 2026 The MathWorks, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. In all cases, the software is, and all modifications and derivatives of the software shall be, licensed to you solely for use in conjunction with MathWorks products and service offerings. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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.
Needs: Needs an MCP server
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/matlab-cosimulate-sumo-simulink · 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 or MathWorks.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-cosimulate-sumo-simulink.zip