| | |
| | | vo.setXduration(String.format("%.2f", crnProtocol.getXDuration())); // 走行时长(H) |
| | | vo.setYduration(String.format("%.2f", crnProtocol.getYDuration())); // 升降时长(H) |
| | | vo.setTaskReceive(crnProtocol.getTaskReceive()); |
| | | vo.setLaserValue(crnProtocol.getLaserValue()); |
| | | |
| | | if (crnProtocol.getModeType().equals(CrnModeType.AUTO)) { |
| | | vo.setDeviceStatus("AUTO"); |
| | |
| | | return R.error("参数不能为空"); |
| | | } |
| | | Set<String> allowKeys = FakeConfigKeys.ALL_KEYS; |
| | | Map<String, String> normalizedMap = new LinkedHashMap<>(); |
| | | for (Map.Entry<String, Object> entry : param.getConfigMap().entrySet()) { |
| | | String key = entry.getKey(); |
| | | if (!allowKeys.contains(key)) { |
| | | return R.error("不支持的配置项: " + key); |
| | | } |
| | | String normalized = normalizeFakeConfigValue(key, entry.getValue()); |
| | | if (!configService.saveConfigValue(key, normalized)) { |
| | | return R.error("保存失败: " + key); |
| | | normalizedMap.put(key, normalizeFakeConfigValue(key, entry.getValue())); |
| | | } |
| | | validateFakeCrnLaserConfig(normalizedMap); |
| | | for (Map.Entry<String, String> entry : normalizedMap.entrySet()) { |
| | | if (!configService.saveConfigValue(entry.getKey(), entry.getValue())) { |
| | | return R.error("保存失败: " + entry.getKey()); |
| | | } |
| | | } |
| | | configService.refreshSystemConfigCache(); |
| | | return getFakeConfig(); |
| | | } |
| | | |
| | | private void validateFakeCrnLaserConfig(Map<String, String> normalizedMap) { |
| | | long bayMin = resolveFakeLongValue(normalizedMap, FakeConfigKeys.FAKE_CRN_BAY_MIN); |
| | | long bayMax = resolveFakeLongValue(normalizedMap, FakeConfigKeys.FAKE_CRN_BAY_MAX); |
| | | long laserMin = resolveFakeLongValue(normalizedMap, FakeConfigKeys.FAKE_CRN_LASER_MIN); |
| | | long laserMax = resolveFakeLongValue(normalizedMap, FakeConfigKeys.FAKE_CRN_LASER_MAX); |
| | | if (bayMax <= bayMin) { |
| | | throw new CoolException("堆垛机 bay 最大值必须大于最小值"); |
| | | } |
| | | if (laserMax <= laserMin) { |
| | | throw new CoolException("堆垛机镭射最大值必须大于最小值"); |
| | | } |
| | | } |
| | | |
| | | private long resolveFakeLongValue(Map<String, String> normalizedMap, String key) { |
| | | String value = normalizedMap.get(key); |
| | | if (value == null) { |
| | | value = configService.getConfigValue(key, FakeConfigKeys.DEFAULTS.get(key)); |
| | | } |
| | | return Long.parseLong(value); |
| | | } |
| | | |
| | | private String normalizeFakeConfigValue(String key, Object rawValue) { |
| | | if (rawValue == null) { |
| | | throw new CoolException(key + " 参数不能为空"); |
| | |
| | | |
| | | private Integer taskReceive; |
| | | |
| | | // 镭射值 |
| | | private Integer laserValue; |
| | | |
| | | // 设备状态-用于前端显示 |
| | | private String deviceStatus = "OFFLINE"; |
| | | |
| | |
| | | public Integer taskReceive; |
| | | |
| | | /** |
| | | * 镭射值 |
| | | */ |
| | | private Integer laserValue; |
| | | |
| | | /** |
| | | * 日志采集时间 |
| | | */ |
| | | private Long deviceDataLog = System.currentTimeMillis(); |
| | |
| | | */ |
| | | public Integer taskReceive; |
| | | |
| | | /** |
| | | * 镭射值 |
| | | */ |
| | | private Integer laserValue; |
| | | |
| | | private Integer temp1; |
| | | |
| | | private Integer temp2; |
| | |
| | | public static final String FAKE_CRN_LEVEL_STEP_DURATION_MS = "fakeCrnLevelStepDurationMs"; |
| | | public static final String FAKE_CRN_BAY_STEP_DURATION_MS = "fakeCrnBayStepDurationMs"; |
| | | public static final String FAKE_CRN_RESET_DURATION_MS = "fakeCrnResetDurationMs"; |
| | | public static final String FAKE_CRN_BAY_MIN = "fakeCrnBayMin"; |
| | | public static final String FAKE_CRN_BAY_MAX = "fakeCrnBayMax"; |
| | | public static final String FAKE_CRN_LASER_MIN = "fakeCrnLaserMin"; |
| | | public static final String FAKE_CRN_LASER_MAX = "fakeCrnLaserMax"; |
| | | |
| | | public static final String FAKE_DUAL_CRN_COMMAND_WAIT_MS = "fakeDualCrnCommandWaitMs"; |
| | | public static final String FAKE_DUAL_CRN_TRANSFER_DURATION_MS = "fakeDualCrnTransferDurationMs"; |
| | |
| | | defaults.put(FAKE_CRN_LEVEL_STEP_DURATION_MS, "1000"); |
| | | defaults.put(FAKE_CRN_BAY_STEP_DURATION_MS, "1000"); |
| | | defaults.put(FAKE_CRN_RESET_DURATION_MS, "0"); |
| | | defaults.put(FAKE_CRN_BAY_MIN, "1"); |
| | | defaults.put(FAKE_CRN_BAY_MAX, "100"); |
| | | defaults.put(FAKE_CRN_LASER_MIN, "100"); |
| | | defaults.put(FAKE_CRN_LASER_MAX, "10000"); |
| | | defaults.put(FAKE_DUAL_CRN_COMMAND_WAIT_MS, "200"); |
| | | defaults.put(FAKE_DUAL_CRN_TRANSFER_DURATION_MS, "2000"); |
| | | defaults.put(FAKE_DUAL_CRN_PICK_DURATION_MS, "3000"); |
| | |
| | | FAKE_CRN_LEVEL_STEP_DURATION_MS, |
| | | FAKE_CRN_BAY_STEP_DURATION_MS, |
| | | FAKE_CRN_RESET_DURATION_MS, |
| | | FAKE_CRN_BAY_MIN, |
| | | FAKE_CRN_BAY_MAX, |
| | | FAKE_CRN_LASER_MIN, |
| | | FAKE_CRN_LASER_MAX, |
| | | FAKE_DUAL_CRN_COMMAND_WAIT_MS, |
| | | FAKE_DUAL_CRN_TRANSFER_DURATION_MS, |
| | | FAKE_DUAL_CRN_PICK_DURATION_MS, |
| | |
| | | private long levelStepDurationMs() { return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_CRN_LEVEL_STEP_DURATION_MS); } |
| | | private long bayStepDurationMs() { return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_CRN_BAY_STEP_DURATION_MS); } |
| | | private long resetDurationMs() { return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_CRN_RESET_DURATION_MS); } |
| | | private long bayMin() { return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_CRN_BAY_MIN); } |
| | | private long bayMax() { return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_CRN_BAY_MAX); } |
| | | private long laserMin() { return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_CRN_LASER_MIN); } |
| | | private long laserMax() { return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_CRN_LASER_MAX); } |
| | | |
| | | public ZyCrnFakeConnect(DeviceConfig deviceConfig) { |
| | | this.deviceConfig = deviceConfig; |
| | | this.crnStatus = JSON.parseObject(deviceConfig.getFakeInitStatus(), ZyCrnStatusEntity.class); |
| | | if (this.crnStatus != null && this.crnStatus.getBay() != null) { |
| | | updateLaserByBay(this.crnStatus.getBay()); |
| | | } |
| | | } |
| | | |
| | | private void updateLaserByBay(int bay) { |
| | | long bayMin = bayMin(); |
| | | long bayMax = bayMax(); |
| | | long laserMin = laserMin(); |
| | | long laserMax = laserMax(); |
| | | if (bayMax <= bayMin || laserMax <= laserMin) { |
| | | this.crnStatus.setLaserValue((int) laserMin); |
| | | return; |
| | | } |
| | | long normalizedBay = Math.max(bayMin, Math.min(bayMax, bay)); |
| | | double ratio = (double) (normalizedBay - bayMin) / (double) (bayMax - bayMin); |
| | | long computed = Math.round(laserMin + ratio * (laserMax - laserMin)); |
| | | long clamped = Math.max(laserMin, Math.min(laserMax, computed)); |
| | | this.crnStatus.setLaserValue((int) clamped); |
| | | } |
| | | |
| | | @Override |
| | |
| | | for(int i = 0; i < moveLength; i++) { |
| | | initSourcePosY++; |
| | | this.crnStatus.setBay(initSourcePosY); |
| | | updateLaserByBay(initSourcePosY); |
| | | sleep(bayStepDurationMs()); |
| | | if (Thread.currentThread().isInterrupted()) { |
| | | return; |
| | |
| | | for(int i = 0; i < moveLength; i++) { |
| | | initSourcePosY--; |
| | | this.crnStatus.setBay(initSourcePosY); |
| | | updateLaserByBay(initSourcePosY); |
| | | sleep(bayStepDurationMs()); |
| | | if (Thread.currentThread().isInterrupted()) { |
| | | return; |
| | |
| | | crnProtocol.setWalkPos(crnStatus.getWalkPos()); |
| | | crnProtocol.setLoaded(crnStatus.getLoaded()); |
| | | crnProtocol.setAlarm(crnStatus.getAlarm()); |
| | | crnProtocol.setLaserValue(crnStatus.getLaserValue()); |
| | | crnProtocol.setTemp1(crnStatus.getTemp1()); |
| | | crnProtocol.setTemp2(crnStatus.getTemp2()); |
| | | crnProtocol.setTemp3(crnStatus.getTemp3()); |
| | |
| | | crnProtocol.setWalkPos(crnStatus.getWalkPos()); |
| | | crnProtocol.setLoaded(crnStatus.getLoaded()); |
| | | crnProtocol.setAlarm(crnStatus.getAlarm()); |
| | | crnProtocol.setLaserValue(crnStatus.getLaserValue()); |
| | | crnProtocol.setTemp1(crnStatus.getTemp1()); |
| | | crnProtocol.setTemp2(crnStatus.getTemp2()); |
| | | crnProtocol.setTemp3(crnStatus.getTemp3()); |
| | |
| | | # 系统版本信息 |
| | | app: |
| | | version: 3.0.0.5 |
| | | version: 3.0.0.6 |
| | | version-type: prd # prd 或 dev |
| | | i18n: |
| | | default-locale: zh-CN |
| | |
| | | WHERE NOT EXISTS (SELECT 1 FROM sys_config WHERE code = 'fakeCrnResetDurationMs'); |
| | | |
| | | INSERT INTO sys_config(name, code, value, type, status, select_type) |
| | | SELECT '单工位堆垛机bay最小值', 'fakeCrnBayMin', '1', 1, 1, 'fake' |
| | | FROM dual |
| | | WHERE NOT EXISTS (SELECT 1 FROM sys_config WHERE code = 'fakeCrnBayMin'); |
| | | |
| | | INSERT INTO sys_config(name, code, value, type, status, select_type) |
| | | SELECT '单工位堆垛机bay最大值', 'fakeCrnBayMax', '100', 1, 1, 'fake' |
| | | FROM dual |
| | | WHERE NOT EXISTS (SELECT 1 FROM sys_config WHERE code = 'fakeCrnBayMax'); |
| | | |
| | | INSERT INTO sys_config(name, code, value, type, status, select_type) |
| | | SELECT '单工位堆垛机镭射最小值', 'fakeCrnLaserMin', '100', 1, 1, 'fake' |
| | | FROM dual |
| | | WHERE NOT EXISTS (SELECT 1 FROM sys_config WHERE code = 'fakeCrnLaserMin'); |
| | | |
| | | INSERT INTO sys_config(name, code, value, type, status, select_type) |
| | | SELECT '单工位堆垛机镭射最大值', 'fakeCrnLaserMax', '10000', 1, 1, 'fake' |
| | | FROM dual |
| | | WHERE NOT EXISTS (SELECT 1 FROM sys_config WHERE code = 'fakeCrnLaserMax'); |
| | | |
| | | INSERT INTO sys_config(name, code, value, type, status, select_type) |
| | | SELECT '双工位堆垛机互斥轮询间隔(毫秒)', 'fakeDualCrnCommandWaitMs', '200', 1, 1, 'fake' |
| | | FROM dual |
| | | WHERE NOT EXISTS (SELECT 1 FROM sys_config WHERE code = 'fakeDualCrnCommandWaitMs'); |
| | |
| | | { label: "目标库位", value: this.orDash(item.locNo) }, |
| | | { label: "是否有物", value: this.orDash(item.loading) }, |
| | | { label: "任务接收", value: this.orDash(item.taskReceive) }, |
| | | { label: "镭射值", value: this.orDash(item.laserValue) }, |
| | | { label: "列", value: this.orDash(item.bay) }, |
| | | { label: "层", value: this.orDash(item.lev) }, |
| | | { label: "货叉定位", value: this.orDash(item.forkOffset) }, |
| | |
| | | { |
| | | key: 'crn', |
| | | title: '单工位堆垛机', |
| | | desc: '控制单工位堆垛机的取放货、Y 轴和 Z 轴节奏。', |
| | | desc: '控制单工位堆垛机的取放货、Y 轴和 Z 轴节奏,并根据 bay 线性计算仿真镭射值。', |
| | | items: [ |
| | | { code: 'fakeCrnFetchPutDurationMs', name: '取放货耗时', desc: '单次取货或放货动作耗时。', unit: 'ms', min: 0, max: 600000 }, |
| | | { code: 'fakeCrnBayStepDurationMs', name: 'Y轴每步耗时', desc: '堆垛机 bay 方向单步移动耗时。', unit: 'ms', min: 0, max: 600000 }, |
| | | { code: 'fakeCrnLevelStepDurationMs', name: 'Z轴每步耗时', desc: '堆垛机 level 方向单步移动耗时。', unit: 'ms', min: 0, max: 600000 }, |
| | | { code: 'fakeCrnResetDurationMs', name: '复位耗时', desc: '单工位堆垛机复位命令耗时。', unit: 'ms', min: 0, max: 600000 } |
| | | { code: 'fakeCrnResetDurationMs', name: '复位耗时', desc: '单工位堆垛机复位命令耗时。', unit: 'ms', min: 0, max: 600000 }, |
| | | { code: 'fakeCrnBayMin', name: 'bay最小值', desc: '仿真镭射换算使用的 bay 最小边界。', min: 0, max: 100000 }, |
| | | { code: 'fakeCrnBayMax', name: 'bay最大值', desc: '仿真镭射换算使用的 bay 最大边界。', min: 0, max: 100000 }, |
| | | { code: 'fakeCrnLaserMin', name: '镭射最小值', desc: 'bay 到最小边界时对应的仿真镭射值。', min: 0, max: 1000000 }, |
| | | { code: 'fakeCrnLaserMax', name: '镭射最大值', desc: 'bay 到最大边界时对应的仿真镭射值。', min: 0, max: 1000000 } |
| | | ] |
| | | }, |
| | | { |
| | |
| | | } |
| | | }, this); |
| | | }, this); |
| | | var bayMin = parseInt(payload.fakeCrnBayMin, 10); |
| | | var bayMax = parseInt(payload.fakeCrnBayMax, 10); |
| | | var laserMin = parseInt(payload.fakeCrnLaserMin, 10); |
| | | var laserMax = parseInt(payload.fakeCrnLaserMax, 10); |
| | | if (bayMax <= bayMin) { |
| | | throw new Error('堆垛机 bay 最大值必须大于最小值'); |
| | | } |
| | | if (laserMax <= laserMin) { |
| | | throw new Error('堆垛机镭射最大值必须大于最小值'); |
| | | } |
| | | return payload; |
| | | }, |
| | | saveConfig: function () { |
| | |
| | | <div class="toolbar-left"> |
| | | <el-tag size="small" :type="statusInfo.isFake ? 'success' : 'info'">{{ statusInfo.isFake ? '仿真模式' : '非仿真模式' }}</el-tag> |
| | | <el-tag size="small" :type="statusInfo.running ? 'danger' : 'warning'">{{ statusInfo.running ? '运行中' : '未运行' }}</el-tag> |
| | | <span class="toolbar-tip">开关项保存为 Y/N,时间项单位均为毫秒。</span> |
| | | <span class="toolbar-tip">开关项保存为 Y/N,时间项单位均为毫秒</span> |
| | | </div> |
| | | <div> |
| | | <el-button size="small" @click="reloadData" :loading="loading">刷新</el-button> |