use super::{
agent_core::{AgentCore, AgentCoreConfig},
global_route_planner::GlobalRoutePlanner,
local_planner::LocalPlannerConfig,
types::{Agent, RoadOption},
};
use crate::{
agents::tools::get_speed,
client::{ActorBase, Map, Vehicle, Waypoint},
error::Result,
geom::Location,
rpc::VehicleControl,
};
#[derive(Debug, Clone)]
pub struct ConstantVelocityAgentConfig {
pub target_speed: f32,
pub use_basic_behavior: bool,
pub core_config: AgentCoreConfig,
pub local_config: LocalPlannerConfig,
}
impl Default for ConstantVelocityAgentConfig {
fn default() -> Self {
let target_speed_mps = 5.0; Self {
target_speed: target_speed_mps,
use_basic_behavior: false,
core_config: AgentCoreConfig::default(),
local_config: LocalPlannerConfig {
target_speed: target_speed_mps * 3.6, ..Default::default()
},
}
}
}
pub struct ConstantVelocityAgent {
core: AgentCore,
use_basic_behavior: bool,
target_speed: f32, current_speed: f32, is_constant_velocity_active: bool,
}
impl ConstantVelocityAgent {
pub fn new(
vehicle: Vehicle,
config: ConstantVelocityAgentConfig,
map_inst: Option<Map>,
grp_inst: Option<GlobalRoutePlanner>,
) -> Result<Self> {
let target_speed = config.target_speed;
let use_basic_behavior = config.use_basic_behavior;
let core = AgentCore::new(
vehicle,
map_inst,
grp_inst,
config.core_config,
config.local_config,
)?;
Ok(Self {
core,
use_basic_behavior,
target_speed,
current_speed: 0.0,
is_constant_velocity_active: true,
})
}
pub fn set_constant_velocity(&mut self, speed: f32) {
self.target_speed = speed;
self.core.local_planner.set_speed(speed * 3.6);
self.is_constant_velocity_active = true;
}
pub fn set_target_speed(&mut self, speed_kmh: f32) {
self.set_constant_velocity(speed_kmh / 3.6);
}
pub fn follow_speed_limits(&mut self, value: bool) {
self.core.local_planner.follow_speed_limits(value);
}
pub fn set_destination(
&mut self,
end_location: Location,
start_location: Option<Location>,
clean_queue: bool,
) -> Result<()> {
let start_location = if let Some(loc) = start_location {
loc
} else if clean_queue {
if let Some((wp, _)) = self
.core
.local_planner
.get_incoming_waypoint_and_direction(0)
{
wp.transform().location
} else {
self.core.vehicle.transform()?.location
}
} else if let Some((wp, _)) = self.core.local_planner.get_plan().last() {
wp.transform().location
} else {
self.core.vehicle.transform()?.location
};
let route = self
.core
.global_planner
.trace_route(start_location, end_location)?;
self.core
.local_planner
.set_global_plan(route, true, clean_queue);
Ok(())
}
pub fn set_global_plan(
&mut self,
plan: Vec<(Waypoint, RoadOption)>,
stop_waypoint_creation: bool,
clean_queue: bool,
) {
self.core
.local_planner
.set_global_plan(plan, stop_waypoint_creation, clean_queue);
}
pub fn trace_route(
&self,
start_waypoint: &Waypoint,
end_waypoint: &Waypoint,
) -> Result<Vec<(Waypoint, RoadOption)>> {
let start_location = start_waypoint.transform().location;
let end_location = end_waypoint.transform().location;
self.core
.global_planner
.trace_route(start_location, end_location)
}
pub fn done(&self) -> bool {
self.core.local_planner.done()
}
pub fn run_step(&mut self) -> Result<VehicleControl> {
self.run_step_with_debug(false)
}
pub fn run_step_with_debug(&mut self, debug: bool) -> Result<VehicleControl> {
self.current_speed = get_speed(&self.core.vehicle) / 3.6;
if !self.is_constant_velocity_active && self.use_basic_behavior {
return self.run_basic_behavior(debug);
}
let mut hazard_speed = self.target_speed * 3.6;
if !self.core.ignore_vehicles {
let max_distance = 10.0; let result = self.core.vehicle_obstacle_detected(max_distance)?;
if result.obstacle_was_found {
hazard_speed = (self.target_speed * 0.5) * 3.6; if debug {
println!("ConstantVelocityAgent: Obstacle detected, reducing speed");
}
}
}
self.core.local_planner.set_speed(hazard_speed);
self.core.local_planner.run_step(debug)
}
fn run_basic_behavior(&mut self, debug: bool) -> Result<VehicleControl> {
let mut hazard_detected = false;
let vehicle_speed = get_speed(&self.core.vehicle) / 3.6; let max_vehicle_distance =
self.core.base_vehicle_threshold + self.core.speed_ratio * vehicle_speed;
let obstacle_result = self.core.vehicle_obstacle_detected(max_vehicle_distance)?;
if obstacle_result.obstacle_was_found {
hazard_detected = true;
if debug {
println!(
"ConstantVelocityAgent: Vehicle obstacle at {:.1}m",
obstacle_result.distance
);
}
}
let max_tlight_distance =
self.core.base_tlight_threshold + self.core.speed_ratio * vehicle_speed;
let traffic_light_result = self.core.affected_by_traffic_light(max_tlight_distance)?;
if traffic_light_result.traffic_light_was_found {
hazard_detected = true;
if debug {
println!("ConstantVelocityAgent: Red traffic light detected");
}
}
let mut control = self.core.local_planner.run_step(debug)?;
if hazard_detected {
control.throttle = 0.0;
control.brake = self.core.max_brake;
if debug {
println!("ConstantVelocityAgent: Emergency stop applied");
}
}
Ok(control)
}
pub fn ignore_traffic_lights(&mut self, active: bool) {
self.core.ignore_traffic_lights(active);
}
pub fn ignore_stop_signs(&mut self, active: bool) {
self.core.ignore_stop_signs(active);
}
pub fn ignore_vehicles(&mut self, active: bool) {
self.core.ignore_vehicles(active);
}
}
impl Agent for ConstantVelocityAgent {
fn run_step(&mut self) -> Result<VehicleControl> {
self.run_step()
}
fn done(&self) -> bool {
self.done()
}
fn set_destination(
&mut self,
end_location: Location,
start_location: Option<Location>,
clean_queue: bool,
) -> Result<()> {
self.set_destination(end_location, start_location, clean_queue)
}
fn set_target_speed(&mut self, speed: f32) {
self.set_target_speed(speed)
}
fn set_global_plan(
&mut self,
plan: Vec<(Waypoint, RoadOption)>,
stop_waypoint_creation: bool,
clean_queue: bool,
) {
self.set_global_plan(plan, stop_waypoint_creation, clean_queue)
}
fn trace_route(
&self,
start_waypoint: &Waypoint,
end_waypoint: &Waypoint,
) -> Result<Vec<(Waypoint, RoadOption)>> {
self.trace_route(start_waypoint, end_waypoint)
}
fn ignore_traffic_lights(&mut self, active: bool) {
self.ignore_traffic_lights(active)
}
fn ignore_stop_signs(&mut self, active: bool) {
self.ignore_stop_signs(active)
}
fn ignore_vehicles(&mut self, active: bool) {
self.ignore_vehicles(active)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_constant_velocity_agent_config_default() {
let config = ConstantVelocityAgentConfig::default();
assert_eq!(config.target_speed, 5.0); assert!(!config.use_basic_behavior);
}
#[test]
fn test_speed_conversion() {
let speed_mps = 10.0;
let speed_kmh = speed_mps * 3.6;
assert_eq!(speed_kmh, 36.0);
}
}