use carla::{
client::{Client, WalkerAIController},
geom::{Location, Transform},
rpc::Command,
};
use rand::RngExt;
use std::{thread, time::Duration};
const NUM_VEHICLES: usize = 30;
const NUM_WALKERS: usize = 50;
const SIMULATION_DURATION_SECS: u64 = 60;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Traffic Generation Example");
println!("==========================\n");
let mut client = Client::connect("localhost", 2000, None)?;
let mut world = client.world()?;
let mut rng = rand::rng();
println!("Connected to CARLA simulator");
println!("Map: {}\n", world.map()?.name());
world.set_pedestrians_seed(rng.random_range(0..100000))?;
world.set_pedestrians_cross_factor(0.2)?;
let bp_lib = world.blueprint_library()?;
let spawn_points = world.map()?.recommended_spawn_points()?;
println!("=== Spawning {} Vehicles ===", NUM_VEHICLES);
let vehicle_blueprints = bp_lib.filter("vehicle.*")?;
if vehicle_blueprints.is_empty() {
return Err("No vehicle blueprints found".into());
}
let mut vehicle_spawn_commands = Vec::new();
for i in 0..NUM_VEHICLES.min(spawn_points.len()) {
let vehicle_bp = vehicle_blueprints
.get(rng.random_range(0..vehicle_blueprints.len()))?
.ok_or("Failed to get vehicle blueprint")?;
let spawn_point = spawn_points.get(i).ok_or("No spawn point available")?;
vehicle_spawn_commands.push(Command::spawn_actor(
vehicle_bp.clone(),
spawn_point.clone(),
None,
));
}
println!("Spawning vehicles in batch...");
let vehicle_responses = client.apply_batch_sync(vehicle_spawn_commands, false)?;
let mut vehicle_ids = Vec::new();
for (i, response) in vehicle_responses.iter().enumerate() {
if let Some(actor_id) = response.actor_id() {
vehicle_ids.push(actor_id);
if i % 10 == 0 {
println!(" Spawned {} vehicles...", i + 1);
}
} else if let Some(error) = response.error() {
eprintln!(" Failed to spawn vehicle {}: {}", i, error);
}
}
println!("✓ Successfully spawned {} vehicles\n", vehicle_ids.len());
println!("Enabling autopilot for vehicles...");
let mut autopilot_commands = Vec::new();
for &vehicle_id in &vehicle_ids {
autopilot_commands.push(Command::set_autopilot(vehicle_id, true, 8000));
}
client.apply_batch_sync(autopilot_commands, false)?;
println!("✓ Autopilot enabled\n");
println!("=== Spawning {} Walkers ===", NUM_WALKERS);
let walker_blueprints = bp_lib.filter("walker.pedestrian.*")?;
if walker_blueprints.is_empty() {
return Err("No walker blueprints found".into());
}
let mut walker_spawn_commands = Vec::new();
for _ in 0..NUM_WALKERS {
let walker_bp = walker_blueprints
.get(rng.random_range(0..walker_blueprints.len()))?
.ok_or("Failed to get walker blueprint")?;
let location = world.random_location_from_navigation()?;
let rotation = carla::geom::Rotation {
pitch: 0.0,
yaw: 0.0,
roll: 0.0,
};
let transform = Transform { location, rotation };
walker_spawn_commands.push(Command::spawn_actor(walker_bp.clone(), transform, None));
}
println!("Spawning walkers in batch...");
let walker_responses = client.apply_batch_sync(walker_spawn_commands, false)?;
let mut walker_ids = Vec::new();
for (i, response) in walker_responses.iter().enumerate() {
if let Some(actor_id) = response.actor_id() {
walker_ids.push(actor_id);
if i % 10 == 0 {
println!(" Spawned {} walkers...", i + 1);
}
}
}
println!("✓ Successfully spawned {} walkers\n", walker_ids.len());
println!("=== Spawning Walker AI Controllers ===");
let controller_bp = bp_lib
.find("controller.ai.walker")?
.ok_or("Walker AI controller blueprint not found")?;
let mut controller_spawn_commands = Vec::new();
for &walker_id in &walker_ids {
let zero_transform = Transform {
location: Location {
x: 0.0,
y: 0.0,
z: 0.0,
},
rotation: carla::geom::Rotation {
pitch: 0.0,
yaw: 0.0,
roll: 0.0,
},
};
controller_spawn_commands.push(Command::spawn_actor(
controller_bp.clone(),
zero_transform,
Some(walker_id),
));
}
println!("Spawning AI controllers in batch...");
let controller_responses = client.apply_batch_sync(controller_spawn_commands, false)?;
let mut controller_ids = Vec::new();
for response in controller_responses {
if let Some(actor_id) = response.actor_id() {
controller_ids.push(actor_id);
}
}
println!(
"✓ Successfully spawned {} AI controllers\n",
controller_ids.len()
);
println!("=== Starting Walker AI ===");
thread::sleep(Duration::from_millis(500));
let mut walker_controllers = Vec::new();
for &controller_id in &controller_ids {
if let Ok(Some(actor)) = world.actor(controller_id)
&& let Ok(controller) = WalkerAIController::try_from(actor)
{
controller.start()?;
let speed = rng.random_range(0.5..2.0);
controller.set_max_speed(speed)?;
if let Some(destination) = controller.get_random_location()? {
controller.go_to_location(&destination)?;
}
walker_controllers.push(controller);
}
}
println!(
"✓ Started {} walker AI controllers\n",
walker_controllers.len()
);
println!("=== Traffic Active ===");
println!(
"Running simulation for {} seconds...\n",
SIMULATION_DURATION_SECS
);
for elapsed in 0..SIMULATION_DURATION_SECS {
thread::sleep(Duration::from_secs(1));
if elapsed % 10 == 0 && elapsed > 0 {
println!(
"[{:02}:{:02}] Traffic active - {} vehicles, {} walkers",
elapsed / 60,
elapsed % 60,
vehicle_ids.len(),
walker_ids.len()
);
}
}
println!("\n=== Cleaning Up ===");
println!("Stopping walker AI controllers...");
for controller in walker_controllers {
controller.stop()?;
}
println!("Destroying all spawned actors...");
let mut destroy_commands = Vec::new();
for &controller_id in &controller_ids {
destroy_commands.push(Command::destroy_actor(controller_id));
}
for &walker_id in &walker_ids {
destroy_commands.push(Command::destroy_actor(walker_id));
}
for &vehicle_id in &vehicle_ids {
destroy_commands.push(Command::destroy_actor(vehicle_id));
}
client.apply_batch_sync(destroy_commands, false)?;
println!("✓ Cleanup complete\n");
println!("=== Traffic Generation Demo Complete ===");
println!("\nSummary:");
println!(" {} vehicles spawned with autopilot", vehicle_ids.len());
println!(" {} walkers spawned with AI control", walker_ids.len());
println!(" {} AI controllers created", controller_ids.len());
println!(
" Simulation duration: {} seconds",
SIMULATION_DURATION_SECS
);
Ok(())
}