| Crates.io | micro_traffic_sim_core |
| lib.rs | micro_traffic_sim_core |
| version | 0.1.8 |
| created_at | 2025-11-05 15:51:51.167518+00 |
| updated_at | 2026-01-15 10:00:03.926238+00 |
| description | Core library for microscopic traffic simulation via cellular automata. |
| homepage | https://github.com/LdDl/micro_traffic_sim_core |
| repository | https://github.com/LdDl/micro_traffic_sim_core |
| max_upload_size | |
| id | 1918183 |
| size | 3,868,587 |
API may change since project is in early stages.
Table of contents
micro_traffic_sim_core is a Rust core library for microscopic traffic simulation (NaSch-like cellular automata and agent-based behaviours). The codebase contains utilities for grids, agents, intentions, conflicts, pathfinding, and session simulation.
Features:
| Simple coordinated zone | Simple ring-like grid |
|---|---|
![]() |
![]() |
| NaSch one-lane road | NaSch two-lane road |
|---|---|
![]() |
![]() |
| Merging roads |
|---|
| Multi-cell vehicles with tail mechanics demonstration |
|---|
Disclaimer: Repository documentation will have a lot of technical details in text form since this is a computational core which will not be used by end-users directly, but rather integrated into service of some sort (gRPC/REST).
Top-level modules are exported from src/lib.rs.
Examples live under the examples/ directory. Notable examples:
examples/nasch-one-lane/main.rs - minimal one-lane NaSch exampleexamples/nasch-two-lanes/main.rs - minimal two-lane NaSch exampleexamples/nasch-lanes-merge/main.rs - merging two lanes into oneexamples/nasch-roads-merge/main.rs - merging two roads into oneexamples/ring/main.rs - ring-like road networkexamples/tutorial/main.rs - complete tutorial with grid creation, trips, traffic lights, and CSV-like outputexamples/all-tail - multi-cell vehicles demonstration with tail mechanics, merge conflicts, and crossing scenariosBenchmarks:
Prerequisites
rustup + cargo)hyperfine for repeated benchmarkingBuild and run an example (prints CSV-like step output).
Run directly (debug):
cargo run --example nasch-one-lane
Capture output to a file (useful for plotting):
cargo run --example nasch-one-lane > examples/nasch-one-lane/output.txt
cargo build --release --example nasch-one-lane
./target/release/examples/nasch-one-lane
hyperfine -i --shell=none --output=pipe --runs 30 --warmup 2 -n "Rust NaSch version" "./target/release/examples/nasch-one-lane"
Add to Cargo.toml:
[dependencies]
micro_traffic_sim_core = "0.1.2"
Every simulation follows this pattern:
The full example for grid basics is in examples/grid-basics.
The full example for whole simulation is in examples/tutorial.
Before we continue it is worth to mention that the simulation session supports verbose logging at different levels. This can be very useful for debugging and understanding the simulation flow.
Currently supported levels are:
VerboseLevel::None - No loggingVerboseLevel::Main - Main simulation pipeline steps.VerboseLevel::Additional - More detailed logging: loops of main steps.VerboseLevel::Detailed - Additional detailed logging: internal computations.How to set verbose level:
use micro_traffic_sim_core::verbose::VerboseLevel;
/* ... */
fn main () {
/* ... */
let mut session = Session::new(grids_storage, None); // Internal session's logger will be set to None automatically
session.set_verbose_level(VerboseLevel::Main); // Set desired level here
/* ... */
}
The grid represents your road network as a collection of connected cells. Each cell is a discrete unit where vehicles can be positioned.
/* ... */
use micro_traffic_sim_core::geom::new_point;
use micro_traffic_sim_core::grid::{cell::Cell, road_network::GridRoads, zones::ZoneType};
/* ... */
fn main() {
/* ... */
let mut grid = GridRoads::new();
let mut cell_id = 1;
let cell = Cell::new(cell_id)
.with_point(new_point(1.0, 1.0, None))
.with_zone_type(ZoneType::Birth)
.with_speed_limit(3)
.with_forward_node(2)
.with_left_node(7)
.with_right_node(-1)
.with_meso_link_id(100500)
.build();
grid.add_cell(cell);
cell_id += 1;
/* ... */
}
/* ... */
Cell attributes explained:
id: Unique identifier for referencing this cell from other cells (CellID type, which is i64) or by vehicles states in the simulation.
point: Physical coordinates in your coordinate system (PointType - can be geographic with SRID)
type_zone: Defines the cell's role in traffic flow (ZoneType enum). Basic types are:
Birth - Vehicles spawn here (start of road)Death - Vehicles despawn here (end of road)Common - Regular road segmentAll types are described in zones.rs.
speed_limit: Maximum velocity in cellular automata units (integer, cells per simulation step)
left_cell: Cell ID for left lane changes (CellID, use -1 if no connection available)
forward_cell: Cell ID for forward movement (CellID, use -1 if no connection available)
right_cell: Cell ID for right lane changes (CellID, use -1 if no connection available)
meso_link_id: Identifier linking the cell to a mesoscopic graph (integer, -1 if not applicable). Could be used for multi-resolution simulations or aggregated traffic flow analysis.
Connection rules:
-1 to indicate "no connection available" for any cell referenceConflict zones handle situations where vehicle paths intersect, defining priority rules for resolution.
use micro_traffic_sim_core::conflict_zones::{ConflictWinnerType, ConflictEdge, ConflictZone};
use std::collections::HashMap;
fn main() {
// ... grid setup code ...
// Create conflict zones storage
let mut conflict_zones = HashMap::new();
// Example: define a conflict where horizontal and vertical traffic intersect
let conflict_zone = ConflictZone::new(
1, // Conflict zone ID
ConflictEdge {
source: 3, // Horizontal approach (cell 3)
target: 4, // Horizontal exit (cell 4)
},
ConflictEdge {
source: 13, // Vertical approach (cell 13)
target: 14, // Vertical exit (cell 14)
},
)
// V1 has priority over H
.with_winner_type(ConflictWinnerType::Second)
.build();
conflict_zones.insert(conflict_zone.get_id(), conflict_zone);
// ... rest of simulation setup ...
}
Traffic lights control vehicle flow through signal groups that manage different approaches.
use micro_traffic_sim_core::traffic_lights::lights::TrafficLight;
use micro_traffic_sim_core::traffic_lights::groups::TrafficLightGroup;
use micro_traffic_sim_core::traffic_lights::signals::SignalType;
use micro_traffic_sim_core::geom::new_point;
use std::collections::HashMap;
fn main() {
// ... grid setup code ...
let mut tls = HashMap::new();
// Create signal groups for horizontal and vertical approaches
let group_h = TrafficLightGroup::new(100) // Horizontal group ID
.with_cells_ids(vec![6]) // Control cell 6
.with_label("Group block H".to_string())
.with_signal(vec![SignalType::Green, SignalType::Red]) // Start green
.build();
let group_v2 = TrafficLightGroup::new(200) // Vertical group ID
.with_cells_ids(vec![23]) // Control cell 23
.with_label("Group block V2".to_string())
.with_signal(vec![SignalType::Red, SignalType::Green]) // Start red (opposite)
.build();
// Create traffic light with timing
let tl = TrafficLight::new(1)
.with_coordinates(new_point(7.0, 4.0, None)) // Physical location
.with_phases_times(vec![5, 5]) // 5 steps green, 5 steps red
.with_groups(vec![group_h, group_v2])
.build();
tls.insert(tl.get_id(), tl);
// ... rest of simulation setup ...
}
Create individual vehicles with specific starting positions and routes.
use micro_traffic_sim_core::agents::Vehicle;
fn main() {
// ... grid setup code ...
// Create a single vehicle
let vehicle = Vehicle::new(0) // Vehicle ID
.with_speed(1) // Current speed
.with_speed_limit(1) // Maximum speed
.with_cell(4) // Starting cell
.with_destination(9) // Goal cell
.build();
// Pass owned vehicles to the session
let vehicles: Vec<Vehicle> = vec![vehicle];
// ... rest of simulation setup ...
}
Multi-cell vehicles:
Vehicles can occupy multiple cells using with_tail_size. The tail follows the head through the road network.
// Create a vehicle with head at cell 5 and tail occupying cells 3 and 4
// Tail order: [furthest from head, ..., closest to head]
let long_vehicle = Vehicle::new(1)
.with_cell(5) // Head position
.with_tail_size(2, vec![3, 4]) // Tail size and initial tail cells
.with_destination(20)
.with_speed(1)
.with_speed_limit(1)
.build();
When a multi-cell vehicle performs a lane change maneuver (LEFT/RIGHT), the tail must complete the same maneuver before the head can perform a conflicting maneuver. This prevents physically impossible situations like turning left while the tail is still turning right.
See examples/all-tail for detailed multi-cell vehicle scenarios.
Create trip generators that spawn vehicles probabilistically during simulation.
use micro_traffic_sim_core::trips::trip::{Trip, TripType};
use micro_traffic_sim_core::agents_types::AgentType;
use micro_traffic_sim_core::behaviour::BehaviourType;
fn main() {
// ... grid setup code ...
// Create trips for different roads
let trips_h = Trip::new(1, 9, TripType::Random) // From cell 1 to cell 9
.with_allowed_agent_type(AgentType::Car)
.with_allowed_behaviour_type(BehaviourType::Cooperative)
.with_probability(0.1) // 10% chance per step
.build();
let trips_v1 = Trip::new(10, 19, TripType::Random) // Vertical road 1
.with_allowed_agent_type(AgentType::Car)
.with_allowed_behaviour_type(BehaviourType::Cooperative)
.with_probability(0.1)
.build();
let trips_v2 = Trip::new(20, 29, TripType::Random) // Vertical road 2
.with_allowed_agent_type(AgentType::Car)
.with_allowed_behaviour_type(BehaviourType::Cooperative)
.with_probability(0.1)
.build();
let trips: Vec<Trip> = vec![trips_h, trips_v1, trips_v2];
// ... rest of simulation setup ...
}
When the grid, vehicles, trips, and traffic lights are ready, initialize the simulation session.
use micro_traffic_sim_core::grid::road_network::GridRoads;
use micro_traffic_sim_core::agents::Vehicle;
use micro_traffic_sim_core::trips::trip::Trip;
use micro_traffic_sim_core::traffic_lights::lights::{TrafficLight, TrafficLightID};
use micro_traffic_sim_core::simulation::session::Session;
use micro_traffic_sim_core::simulation::grids_storage::GridsStorage;
use micro_traffic_sim_core::verbose::VerboseLevel;
use std::collections::HashMap;
fn main () {
let mut grid = GridRoads::new();
// Populate grid with cells
// ...
let vehicles: Vec<Vehicle> = vec![/* ... vehicles ... */];
// Prepare vehicles or use generator
// ...
let trips: Vec<Trip> = vec![/* ... trips ... */];
// Prepare trips
// ...
let tls: HashMap<TrafficLightID, TrafficLight> = HashMap::new();
// Prepare traffic lights
// ...
let grids_storage = GridsStorage::new()
.with_vehicles_net(grid)
.with_tls(tls)
.build();
let mut session = Session::new(grids_storage, None);
session.set_verbose_level(VerboseLevel::Main);
session.add_vehicles(vehicles);
for trip in trips.iter() {
session.add_trip(trip.clone());
}
}
Run the simulation for a defined number of steps, collecting vehicle states at each step.
let steps = 10;
for step in 0..steps {
match session.step() {
Ok(automata_state) => {
for v in automata_state.vehicles {
println!(
"{};{};{};{};{:.5};{}",
step,
v.id,
v.vehicle_type,
v.last_speed,
v.last_angle,
v.last_cell,
);
}
for tl in automata_state.tls {
for group in tl.1 {
let group_id = group.group_id;
let signal = group.last_signal;
println!(
"tl_step;{};{};{};{:.5};{:.5};{}",
step,
tl.0,
group_id,
group.last_position.x,
group.last_position.y,
signal
);
}
}
}
Err(e) => {
eprintln!("Error during simulation step {}: {:?}", step, e);
}
};
}
You can analyze the output data using various tools.
In the basic tutorial examples/tutorial states are aggregated in CSV-like format (with semicolon delimiter) and then visualized with gnuplot(http://www.gnuplot.info/).
In the future, I plan to add example with visualization in the browser using gRPC/WebSockets for integration with server-side.
src/lib.rssrc/geom/point.rssrc/geom/spatial.rssrc/grid/cell.rssrc/grid/road_network.rssrc/shortest_path/router.rssrc/traffic_lights/signals.rssrc/traffic_lights/groups.rssrc/traffic_lights/lights.rssrc/agents/behaviour.rssrc/agents/vehicle.rssrc/agents/vehicles_storage.rssrc/trips/trip.rssrc/intentions/intention.rssrc/intentions/intentions_datastorage.rssrc/intentions/intention_path.rssrc/conflictssrc/conflict_zones/conflict_zones.rssrc/movement/movement.rssrc/simulation/grids_storage.rssrc/simulation/session.rs