道岔仿真逻辑完善
多线程多app实验
This commit is contained in:
parent
3487b8eb1c
commit
072e6ba262
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"rtss",
|
||||||
|
"timestep"
|
||||||
|
]
|
||||||
|
}
|
@ -10,12 +10,12 @@ impl Default for Uid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 两常态位置转换组件,用于像道岔位置,屏蔽门位置等
|
// 两常态位置转换组件,用于像道岔位置,屏蔽门位置等
|
||||||
#[derive(Component, Debug, Clone, PartialEq, Eq, Default)]
|
#[derive(Component, Debug, Clone, PartialEq, Default)]
|
||||||
pub struct TwoNormalPositionsConversion {
|
pub struct TwoNormalPositionsConversion {
|
||||||
// 当前实际位置,百分比值,0-100
|
// 当前实际位置,百分比值,0-100
|
||||||
pub position: i32,
|
pub position: i32,
|
||||||
// 当前转换速度
|
// 当前转换速度
|
||||||
pub velocity: i32,
|
pub velocity: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 道岔设备状态组件
|
// 道岔设备状态组件
|
||||||
|
14
src/main.rs
14
src/main.rs
@ -1,3 +1,15 @@
|
|||||||
|
use std::thread::{self, JoinHandle};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
rtss_simulation::Simulation::new().app.run();
|
let mut list: Vec<JoinHandle<()>> = Vec::new();
|
||||||
|
for i in 0..100 {
|
||||||
|
let thread_handler = thread::spawn(move || {
|
||||||
|
let mut sim = rtss_simulation::Simulation::new(i.to_string());
|
||||||
|
sim.run();
|
||||||
|
});
|
||||||
|
list.push(thread_handler);
|
||||||
|
}
|
||||||
|
for handler in list {
|
||||||
|
handler.join().unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, ops::Deref};
|
||||||
|
|
||||||
use bevy_ecs::{entity::Entity, system::Resource};
|
use bevy_ecs::{entity::Entity, system::Resource};
|
||||||
|
|
||||||
@ -7,3 +7,37 @@ use bevy_ecs::{entity::Entity, system::Resource};
|
|||||||
pub struct EquipmentUidEntityMapping {
|
pub struct EquipmentUidEntityMapping {
|
||||||
pub turnout_mapping: HashMap<String, Entity>,
|
pub turnout_mapping: HashMap<String, Entity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Debug)]
|
||||||
|
pub struct SimulationId(String);
|
||||||
|
|
||||||
|
impl SimulationId {
|
||||||
|
pub fn new(id: String) -> Self {
|
||||||
|
SimulationId(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for SimulationId {
|
||||||
|
type Target = String;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Debug)]
|
||||||
|
pub struct SimulationConfig {
|
||||||
|
// 仿真倍速
|
||||||
|
pub simulation_speed: f32,
|
||||||
|
// 道岔转换总时间,单位ms
|
||||||
|
pub turnout_transform_time: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SimulationConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
SimulationConfig {
|
||||||
|
simulation_speed: 1.0,
|
||||||
|
turnout_transform_time: 3500,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,25 +3,20 @@ use std::time::Duration;
|
|||||||
use crate::{
|
use crate::{
|
||||||
control_simulation, handle_turnout_control, loading, simulation_status_control,
|
control_simulation, handle_turnout_control, loading, simulation_status_control,
|
||||||
turnout_state_update, two_normal_position_transform, EquipmentUidEntityMapping,
|
turnout_state_update, two_normal_position_transform, EquipmentUidEntityMapping,
|
||||||
SimulationControlEvent,
|
SimulationConfig, SimulationControlEvent, SimulationId,
|
||||||
};
|
};
|
||||||
use bevy_app::{prelude::*, ScheduleRunnerPlugin};
|
use bevy_app::{prelude::*, ScheduleRunnerPlugin};
|
||||||
use bevy_ecs::schedule::IntoSystemConfigs;
|
use bevy_ecs::schedule::IntoSystemConfigs;
|
||||||
use bevy_log::LogPlugin;
|
use bevy_log::{debug, LogPlugin};
|
||||||
use bevy_time::{prelude::*, TimePlugin};
|
use bevy_time::{prelude::*, TimePlugin};
|
||||||
|
|
||||||
pub struct Simulation {
|
pub struct Simulation {
|
||||||
|
id: String,
|
||||||
pub app: App,
|
pub app: App,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Simulation {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Simulation {
|
impl Simulation {
|
||||||
pub fn new() -> Self {
|
pub fn new(id: String) -> Self {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
app.add_plugins(ScheduleRunnerPlugin::run_loop(Duration::from_millis(1000)))
|
app.add_plugins(ScheduleRunnerPlugin::run_loop(Duration::from_millis(1000)))
|
||||||
.add_plugins(LogPlugin {
|
.add_plugins(LogPlugin {
|
||||||
@ -31,7 +26,9 @@ impl Simulation {
|
|||||||
.add_plugins(TimePlugin)
|
.add_plugins(TimePlugin)
|
||||||
.insert_resource(Time::<Virtual>::from_max_delta(Duration::from_secs(5)))
|
.insert_resource(Time::<Virtual>::from_max_delta(Duration::from_secs(5)))
|
||||||
.insert_resource(Time::<Fixed>::from_duration(Duration::from_millis(1000)))
|
.insert_resource(Time::<Fixed>::from_duration(Duration::from_millis(1000)))
|
||||||
|
.insert_resource(SimulationId::new(id.clone()))
|
||||||
.insert_resource(EquipmentUidEntityMapping::default())
|
.insert_resource(EquipmentUidEntityMapping::default())
|
||||||
|
.insert_resource(SimulationConfig::default())
|
||||||
.add_event::<SimulationControlEvent>()
|
.add_event::<SimulationControlEvent>()
|
||||||
.add_systems(Startup, loading)
|
.add_systems(Startup, loading)
|
||||||
.add_systems(Update, control_simulation)
|
.add_systems(Update, control_simulation)
|
||||||
@ -41,6 +38,19 @@ impl Simulation {
|
|||||||
)
|
)
|
||||||
.observe(handle_turnout_control)
|
.observe(handle_turnout_control)
|
||||||
.observe(simulation_status_control);
|
.observe(simulation_status_control);
|
||||||
Simulation { app }
|
Simulation { id, app }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
&self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
self.app.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
debug!("close simulation id={}", self.id);
|
||||||
|
self.app.world_mut().trigger(SimulationControlEvent::Exit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,18 +21,16 @@ pub fn control_simulation(
|
|||||||
// debug!("Uid: {:?}, Entity: {:?}", uid, entity);
|
// debug!("Uid: {:?}, Entity: {:?}", uid, entity);
|
||||||
commands.trigger_targets(TurnoutControlEvent::FC, *entity);
|
commands.trigger_targets(TurnoutControlEvent::FC, *entity);
|
||||||
});
|
});
|
||||||
if time.elapsed_seconds() > 13.0 {
|
if time.elapsed_seconds() > 7.0 {
|
||||||
debug!("send exit event");
|
debug!("send exit event");
|
||||||
commands.trigger(SimulationControlEvent::Exit);
|
commands.trigger(SimulationControlEvent::Exit);
|
||||||
}
|
}
|
||||||
// if time.elapsed_seconds() > 10.0 {
|
|
||||||
// commands.trigger(SimulationControlEvent::Pause);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn simulation_status_control(
|
pub fn simulation_status_control(
|
||||||
trigger: Trigger<SimulationControlEvent>,
|
trigger: Trigger<SimulationControlEvent>,
|
||||||
mut time: ResMut<Time<Virtual>>,
|
mut time: ResMut<Time<Virtual>>,
|
||||||
|
sid: Res<crate::SimulationId>,
|
||||||
mut exit: EventWriter<AppExit>,
|
mut exit: EventWriter<AppExit>,
|
||||||
) {
|
) {
|
||||||
match trigger.event() {
|
match trigger.event() {
|
||||||
@ -45,7 +43,7 @@ pub fn simulation_status_control(
|
|||||||
time.unpause();
|
time.unpause();
|
||||||
}
|
}
|
||||||
SimulationControlEvent::Exit => {
|
SimulationControlEvent::Exit => {
|
||||||
debug!("Exiting simulation");
|
debug!("Exiting simulation, id={:?}", *sid);
|
||||||
exit.send(AppExit::Success);
|
exit.send(AppExit::Success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,41 @@
|
|||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
observer::Trigger,
|
observer::Trigger,
|
||||||
system::{Query, ResMut},
|
system::{Query, Res, ResMut},
|
||||||
};
|
};
|
||||||
use bevy_log::debug;
|
use bevy_log::debug;
|
||||||
use bevy_time::{Fixed, Time};
|
use bevy_time::{Fixed, Time};
|
||||||
|
|
||||||
use crate::{events::TurnoutControlEvent, TurnoutState, TwoNormalPositionsConversion, Uid};
|
use crate::{
|
||||||
|
events::TurnoutControlEvent, SimulationConfig, TurnoutState, TwoNormalPositionsConversion, Uid,
|
||||||
|
};
|
||||||
|
|
||||||
// 道岔控制事件处理系统
|
// 道岔控制事件处理系统
|
||||||
pub fn handle_turnout_control(
|
pub fn handle_turnout_control(
|
||||||
trigger: Trigger<TurnoutControlEvent>,
|
trigger: Trigger<TurnoutControlEvent>,
|
||||||
time: ResMut<Time<Fixed>>,
|
time: ResMut<Time<Fixed>>,
|
||||||
|
config: Res<SimulationConfig>,
|
||||||
mut query: Query<(&Uid, &mut TurnoutState, &mut TwoNormalPositionsConversion)>,
|
mut query: Query<(&Uid, &mut TurnoutState, &mut TwoNormalPositionsConversion)>,
|
||||||
) {
|
) {
|
||||||
let (uid, mut state, mut conversion) = query
|
let (uid, mut state, mut conversion) = query
|
||||||
.get_mut(trigger.entity())
|
.get_mut(trigger.entity())
|
||||||
.expect("通过entity获取道岔异常");
|
.expect("通过entity获取道岔异常");
|
||||||
|
let v = calculate_avg_velocity(
|
||||||
|
TWO_NORMAL_POSITION_MAX as f32,
|
||||||
|
config.turnout_transform_time as f32,
|
||||||
|
time.timestep().as_millis() as f32,
|
||||||
|
);
|
||||||
match trigger.event() {
|
match trigger.event() {
|
||||||
TurnoutControlEvent::DC => {
|
TurnoutControlEvent::DC => {
|
||||||
state.dc = true;
|
state.dc = true;
|
||||||
state.fc = false;
|
state.fc = false;
|
||||||
conversion.velocity = -3000 / time.timestep().as_millis() as i32;
|
conversion.velocity = -v;
|
||||||
debug!("道岔定操处理:{:?}", uid);
|
debug!("道岔定操处理:{:?}", uid);
|
||||||
}
|
}
|
||||||
TurnoutControlEvent::FC => {
|
TurnoutControlEvent::FC => {
|
||||||
state.dc = false;
|
state.dc = false;
|
||||||
state.fc = true;
|
state.fc = true;
|
||||||
conversion.velocity = 3000 / time.timestep().as_millis() as i32;
|
conversion.velocity = v;
|
||||||
debug!("道岔反操处理:uid={:?}, conversion={:?}", uid, conversion);
|
debug!("道岔反操处理:uid={:?}, conversion={:?}", uid, conversion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,19 +50,26 @@ pub fn turnout_state_update(
|
|||||||
"更新道岔状态:Uid={:?}, State={:?}, Conversion={:?}",
|
"更新道岔状态:Uid={:?}, State={:?}, Conversion={:?}",
|
||||||
uid, state, conversion
|
uid, state, conversion
|
||||||
);
|
);
|
||||||
if conversion.velocity != 0 {
|
if conversion.position == 0 {
|
||||||
state.db = false;
|
|
||||||
state.fb = false;
|
|
||||||
} else if conversion.position == 0 {
|
|
||||||
state.db = true;
|
state.db = true;
|
||||||
state.fb = false;
|
state.fb = false;
|
||||||
} else if conversion.position == 100 {
|
} else if conversion.position == 100 {
|
||||||
state.db = false;
|
state.db = false;
|
||||||
state.fb = true;
|
state.fb = true;
|
||||||
|
} else {
|
||||||
|
state.db = false;
|
||||||
|
state.fb = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 计算平均速度
|
||||||
|
fn calculate_avg_velocity(total_distance: f32, total_time: f32, time_step: f32) -> f32 {
|
||||||
|
total_distance / (total_time / time_step)
|
||||||
|
}
|
||||||
|
|
||||||
|
const TWO_NORMAL_POSITION_MIN: i32 = 0;
|
||||||
|
const TWO_NORMAL_POSITION_MAX: i32 = 100;
|
||||||
// 两常态位置转换系统
|
// 两常态位置转换系统
|
||||||
pub fn two_normal_position_transform(
|
pub fn two_normal_position_transform(
|
||||||
mut query: Query<(Entity, &Uid, &mut TwoNormalPositionsConversion)>,
|
mut query: Query<(Entity, &Uid, &mut TwoNormalPositionsConversion)>,
|
||||||
@ -64,16 +79,16 @@ pub fn two_normal_position_transform(
|
|||||||
"Entity: {:?}, Uid: {:?}, Conversion: {:?}",
|
"Entity: {:?}, Uid: {:?}, Conversion: {:?}",
|
||||||
entity, uid, conversion
|
entity, uid, conversion
|
||||||
);
|
);
|
||||||
if conversion.velocity == 0 {
|
if conversion.velocity == 0f32 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let p = conversion.position + conversion.velocity;
|
let p = conversion.position + conversion.velocity as i32;
|
||||||
if p > 100 {
|
if p > TWO_NORMAL_POSITION_MAX {
|
||||||
conversion.position = 100;
|
conversion.position = TWO_NORMAL_POSITION_MAX;
|
||||||
conversion.velocity = 0;
|
conversion.velocity = TWO_NORMAL_POSITION_MIN as f32;
|
||||||
} else if p < 0 {
|
} else if p < TWO_NORMAL_POSITION_MIN {
|
||||||
conversion.position = 0;
|
conversion.position = TWO_NORMAL_POSITION_MIN;
|
||||||
conversion.velocity = 0;
|
conversion.velocity = 0 as f32;
|
||||||
} else {
|
} else {
|
||||||
conversion.position = p;
|
conversion.position = p;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user