仿真结构抽象(仿真主线程逻辑调整)

虚拟真实设备逻辑开发
This commit is contained in:
walker-sheng 2021-03-05 16:34:54 +08:00
parent fb7f3fa70c
commit 6abd8254b6
9 changed files with 243 additions and 68 deletions

View File

@ -28,12 +28,12 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
*/
private LocalDateTime systemTime;
private static final int SYSTEM_TIME_RATE = 10;
private static final int SYSTEM_TIME_RATE = 1;
private final AtomicBoolean mainLogicRunning = new AtomicBoolean(false);
/**
* 实际运行间隔单位ns
*/
long runPeriod;
long timeAdd;
/**
* 用来取消仿真线程逻辑定时执行的任务
*/
@ -82,25 +82,40 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
throw new IllegalArgumentException("仿真id不能为空");
}
this.id = id;
this.systemTime = LocalDateTime.now();
this.runAsSpeed(speed);
}
private void runAsSpeed(int speed) {
this.speed = speed;
if (this.future != null) {
if (!this.future.cancel(false)) {
log.error(String.format("仿真旧主线程无法取消"));
}
}
this.updateRunPeriod(speed);
ScheduledFuture<?> scheduledFuture = EXECUTOR.scheduleAtFixedRate(()->this.logic(),
this.runPeriod, this.runPeriod, TimeUnit.NANOSECONDS);
this.future = scheduledFuture;
this.systemTime = LocalDateTime.now();
}
private void updateRunPeriod(int speed) {
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(SYSTEM_TIME_RATE) / speed;
public static void main(String[] args) {
Simulation simulation = new Simulation("1") {
@Override
public String debugStr() {
return null;
}
};
simulation.addJob("b", () -> {
log.info("logic");
}, 500);
simulation.addFixedRateJob("c", () -> {
log.warn("fixed");
}, 1000);
simulation.updateSpeed(5);
simulation.start();
}
private void runAsSpeed() {
if (this.future == null) {
// if (!this.future.cancel(false)) {
// log.error(String.format("仿真旧主线程无法取消"));
// }
ScheduledFuture<?> scheduledFuture = EXECUTOR.scheduleAtFixedRate(()->this.logic(),
this.SYSTEM_TIME_RATE, this.SYSTEM_TIME_RATE, TimeUnit.MILLISECONDS);
this.future = scheduledFuture;
}
this.updateTimeUpdateSpeed(this.speed);
}
private void updateTimeUpdateSpeed(int speed) {
this.timeAdd = TimeUnit.MILLISECONDS.toNanos(SYSTEM_TIME_RATE) * speed;
}
private void logic() {
@ -109,7 +124,7 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
}
try {
this.mainLogicRunning.set(true);
this.systemTime = this.systemTime.plusNanos(TimeUnit.MILLISECONDS.toNanos(SYSTEM_TIME_RATE));
this.systemTime = this.systemTime.plusNanos(timeAdd);
for (SimulationScheduledJob scheduledJob : this.scheduledJobMap.values()) {
if (scheduledJob.isTimeToRun(this.systemTime)) {
scheduledJob.run();
@ -221,6 +236,7 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
*/
public void start() {
this.state.set(RUNNING);
this.runAsSpeed();
}
/**
@ -260,9 +276,10 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
throw new IllegalArgumentException(String.format("speed must small or equal than [%s]", MAX_SPEED));
}
if (this.speed != speed) { // 速度不同重新更改并重新按新速度运行
this.speed = speed;
int state = this.state.get();
this.pause();
this.runAsSpeed(speed);
this.runAsSpeed();
for (SimulationScheduledJob job : this.scheduledJobMap.values()) {
job.updateRunPeriod(speed);
}

View File

@ -46,23 +46,23 @@ final class SimulationScheduledJob implements Runnable {
this(simulation, name, job, rate, false);
}
public static final int TIMEOUT = 10;
public static final long TIMEOUT_NANO = TimeUnit.MILLISECONDS.toNanos(10);
@Override
public void run() {
long start = System.nanoTime();
this.job.run();
long used = System.nanoTime() - start;
if (used > TimeUnit.MILLISECONDS.toNanos(TIMEOUT)) {
log.warn(String.format("仿真任务[%s]执行耗时[%sns]超过[%sms],请检查并调优",
this.name, TimeUnit.NANOSECONDS.toMillis(used), TIMEOUT));
if (used > TIMEOUT_NANO) {
log.warn(String.format("仿真任务[%s]执行耗时[%sns]超过[%sns],请检查并调优",
this.name, used, TIMEOUT_NANO));
}
}
public void updateRunPeriod(int speed) {
if (this.fixed) {
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate);
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate) * speed;
} else {
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate) / speed;
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate);
}
}

View File

@ -1,32 +1,42 @@
package club.joylink.rtss.simulation.rt;
import club.joylink.rtss.services.MapService;
import club.joylink.rtss.simulation.SimulationManager;
import club.joylink.rtss.simulation.rt.srd.SrdService;
import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.map.MapVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Objects;
@Component
public class RtSimulationService {
@Autowired
private MapService mapService;
@Autowired
private SimulationManager simulationManager;
@Autowired
private SrdService srdService;
public RtSimulation create(UserVO userVO) {
public RtSimulation create(UserVO userVO, Long mapId) {
Objects.requireNonNull(mapId);
MapVO mapVO = this.mapService.getMapDetail(mapId);
RtSimulation rtSimulation = new RtSimulation(SimulationIdGenerator.buildId());
this.simulationManager.save(rtSimulation);
this.load(rtSimulation);
this.loadData(rtSimulation, mapVO);
this.srdService.addJobs(rtSimulation);
this.simulationManager.save(rtSimulation);
return rtSimulation;
}
/**
* 加载相关数据
* @param rtSimulation
* @param mapVO
*/
private void load(RtSimulation rtSimulation) {
private void loadData(RtSimulation rtSimulation, MapVO mapVO) {
this.srdService.buildRepository(rtSimulation, mapVO);
}
}

View File

@ -1,10 +1,8 @@
package club.joylink.rtss.simulation.rt.srd;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.rt.RtSimulation;
import club.joylink.rtss.simulation.rt.srd.bo.SrTrain;
import club.joylink.rtss.simulation.rt.srd.bo.SrdRepository;
import club.joylink.rtss.simulation.rt.srd.bo.SrdRepositoryBuilder;
import club.joylink.rtss.simulation.rt.srd.bo.TrackPosition;
import club.joylink.rtss.simulation.rt.srd.bo.*;
import club.joylink.rtss.vo.client.map.MapVO;
import org.springframework.stereotype.Component;
@ -28,14 +26,76 @@ public class SrdService {
public void srTrainRun(SrdRepository repository) {
List<SrTrain> trainList = repository.getTrainList();
for (SrTrain srTrain : trainList) {
if (!srTrain.isUsing()) {
continue;
}
TrackPosition position = srTrain.getPosition();
if (position == null) { // 列车没有位置
continue;
long speed = srTrain.getSpeed();
boolean right = srTrain.isRight();
int cv = this.calculateSpeed(srTrain);
int s = this.calculateLen(cv, TRAIN_RUN_RATE);
TrackPosition np = calculatePosition(position, s, right);
if (np.equals(position) && cv != 0) {
cv = 0;
}
if (srTrain.isNeutralGear()) { // 空挡
continue;
}
srTrain.updatePositionAndSpeed(np, cv);
}
}
private int calculateLen(int cv, int time) {
return cv * time;
}
private int calculateSpeed(SrTrain srTrain) {
long speed = srTrain.getSpeed();
int wa = (int) (10 + speed * 0.001 + speed * speed * 0.0000003); // 阻力所产生的反向加速度
int pa = 0;
if (srTrain.isEb()) {
pa = SrTrain.ES_DEC;
} else {
pa = srTrain.getP() >= 0 ? srTrain.getP() * SrTrain.MAX_ACC : srTrain.getP() * SrTrain.MAX_DEC;
}
int a = pa - wa;
int cv = (int) (speed + a * TRAIN_RUN_RATE); // 当前速度
if (cv < 0) {
cv = 0;
}
return cv;
}
private TrackPosition calculatePosition(TrackPosition position, int s, boolean right) {
if (s == 0) {
return position;
}
SrTrack track = position.getTrack();
int offset = position.getOffset();
if (right) {
offset += s;
} else {
offset -= s;
}
SrTrack base = track;
while (offset < 0 || offset > base.getLen()) {
SrTrack nextTrack = base.queryNextTrack(right);
if (nextTrack == null) {
if (offset < 0) {
offset = 0;
} else {
offset = base.getLen();
}
break;
} else {
if (right) {
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotTrue(offset < 0);
offset -= base.getLen();
} else {
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotTrue(offset > base.getLen());
offset += nextTrack.getLen();
}
base = nextTrack;
}
}
return new TrackPosition(base, offset);
}
}

View File

@ -25,13 +25,21 @@ public class SrTrack extends SrDevice {
*/
SrAXC axc;
/**
* 左侧轨道可能为null
* 左侧直向轨道可能为null
*/
SrTrack left;
SrTrack leftTrack;
/**
* 左侧侧向轨道非道岔的都为null
*/
SrTrack leftFlankTrack;
/**
* 右侧轨道可能为null
*/
SrTrack right;
SrTrack rightTrack;
/**
* 右侧侧向轨道非道岔的都为null
*/
SrTrack rightFlankTrack;
/**
* 关联的道岔是道岔区段才会关联否则为null
*/
@ -45,17 +53,52 @@ public class SrTrack extends SrDevice {
this.axc = axc;
}
public void setLeft(SrTrack left) {
this.left = left;
left.setRight(this);
public void setLeftTrack(SrTrack left) {
this.leftTrack = left;
left.setRightTrack(this);
}
public void setRight(SrTrack right) {
this.right = right;
right.setLeft(this);
public void setLeftFlankTrack(SrTrack leftFlank) {
this.leftFlankTrack = leftFlank;
leftFlank.setRightTrack(this);
}
public void setRightTrack(SrTrack right) {
this.rightTrack = right;
right.setLeftTrack(this);
}
public void setRightFlankTrack(SrTrack rightFlank) {
this.rightFlankTrack = rightFlank;
rightFlank.setLeftTrack(this);
}
public void setTurnout(SrTurnout turnout) {
this.turnout = turnout;
}
public SrTrack queryNextTrack(boolean right) {
if (this.turnout != null) {
if (this.turnout.isNormalPosition()) {
return right ? this.rightTrack : this.leftTrack;
} else if (this.turnout.isReversePosition()) {
if (right) {
if (this.rightFlankTrack != null) {
return this.rightFlankTrack;
} else {
return this.rightTrack;
}
} else {
if (this.leftFlankTrack != null) {
return this.leftFlankTrack;
} else {
return this.leftTrack;
}
}
}
} else {
return right ? this.rightTrack : this.leftTrack;
}
return null;
}
}

View File

@ -7,6 +7,10 @@ import lombok.Getter;
*/
@Getter
public class SrTrain extends SrDevice {
/**
* 是否使用中
*/
boolean using;
/**
* 列车长度,单位mm
@ -15,13 +19,29 @@ public class SrTrain extends SrDevice {
/**
* 列车质量,单位
*/
int mass = 230;
int mass = 224;
/**
* 牵引力,<0为制动
* 最大加速度, 单位mm/s2
*/
int f;
public static final int MAX_ACC = 1600;
/**
* 列车速度
* 最大常用制动加速度, 单位mm/s2
*/
public static final int MAX_DEC = -1200;
/**
* 紧急制动加速度, 单位mm/s2
*/
public static final int ES_DEC = -1500;
/**
* 功率-100 <= p <= 100
*/
int p;
/**
* 是否紧急制动
*/
boolean eb;
/**
* 列车速度,单位mm/s
*/
int speed;
/**
@ -48,4 +68,9 @@ public class SrTrain extends SrDevice {
public boolean isNeutralGear() {
return NEUTRAL == this.gear;
}
public void updatePositionAndSpeed(TrackPosition position, int v) {
this.position = position;
this.speed = v;
}
}

View File

@ -30,18 +30,27 @@ public class SrTurnout extends SrDevice {
super(id, DeviceType.TURNOUT);
}
public void setA(SrTrack a) {
public void setTracks(SrTrack a, SrTrack b, SrTrack c) {
this.a = a;
a.setTurnout(this);
}
public void setB(SrTrack b) {
this.b = b;
b.setTurnout(this);
this.c = c;
if (this.a.leftTrack == null && this.a.rightTrack == null) {
throw new IllegalStateException("道岔a区段两端都没有关联的区段");
}
if (this.a.leftTrack != null) { // a左侧存在
this.a.setRightTrack(this.b);
this.a.setRightFlankTrack(this.c);
} else { // a右侧存在
this.a.setLeftTrack(this.b);
this.a.setLeftFlankTrack(this.c);
}
}
public void setC(SrTrack c) {
this.c = c;
c.setTurnout(this);
public boolean isNormalPosition() {
return NORMAL == this.state.get();
}
public boolean isReversePosition() {
return REVERSE == this.state.get();
}
}

View File

@ -43,13 +43,13 @@ public class SrdRepositoryBuilder {
SrTrack left = trackMap.get(sectionVO.getLeftSectionCode());
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(left,
String.format("区段[%s]的左关联区段[%s]不存在", srTrack.getId(), sectionVO.getLeftSectionCode()));
srTrack.setLeft(left);
srTrack.setLeftTrack(left);
}
if (StringUtils.hasText(sectionVO.getRightSectionCode())) {
SrTrack right = trackMap.get(sectionVO.getRightSectionCode());
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(right,
String.format("区段[%s]的右关联区段[%s]不存在", srTrack.getId(), sectionVO.getRightSectionCode()));
srTrack.setRight(right);
srTrack.setRightTrack(right);
}
// 构建轨道和计轴关系
SrAXC axc;
@ -91,9 +91,7 @@ public class SrdRepositoryBuilder {
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(c,
String.format("道岔[%s]关联区段C[%s]不存在", switchVO.getCode(), switchVO.getSectionCCode()));
SrTurnout turnout = turnoutMap.get(switchVO.getCode());
turnout.setA(a);
turnout.setB(b);
turnout.setC(c);
turnout.setTracks(a, b, c);
}
}

View File

@ -3,4 +3,17 @@ package club.joylink.rtss.simulation.rt.srd.bo;
public class TrackPosition {
SrTrack track;
int offset;
public TrackPosition(SrTrack track, int offset) {
this.track = track;
this.offset = offset;
}
public SrTrack getTrack() {
return track;
}
public int getOffset() {
return offset;
}
}