-
-
-
-
-
+
diff --git a/public/main.js b/public/main.js
index 2142440..47758b2 100644
--- a/public/main.js
+++ b/public/main.js
@@ -13,13 +13,14 @@ ws.onclose = () => {
console.log("Disconnected from server");
};
-$("#submit_user_pwd").on("click", () => {
- const name = $("#username").val();
- const pwd = $("#password").val();
+$("#moveArm").on("click", () => {
+ const x = $("#armX").val();
+ const y = $("#armY").val();
+ const z = $("#armZ").val();
$.ajax({
type: "POST",
- url: "/test",
- data: JSON.stringify({ name, pwd }),
+ url: "/api/debug/railArm",
+ data: JSON.stringify({ x: +x, y: +y, z: +z }),
contentType: "application/json",
success: res => {
console.log("Success", res);
diff --git a/src/config/db.ts b/src/config/db.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/controllers/cmd.ts b/src/controllers/cmd.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/index.ts b/src/index.ts
index f9a794e..17faed5 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -3,46 +3,56 @@ import { Server } from "ws";
import http from "http";
import bodyParser from "body-parser";
+import cmdRouter from "./routes/cmd";
+import debugRouter from "./routes/debug";
+
+import { defaultStatus, StatusDatagram } from "./types/wsTypes";
+import { wsSend } from "./utils/wss";
+
const app = express();
app.use(express.static("public"));
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
-app.get("/", (req, res) => {
- res.send("Hello World!");
-});
-app.post("/test", (req, res) => {
- (req.app.locals["wss"] as Server).clients.forEach(client => {
- if (client.readyState === 1) {
- client.send(JSON.stringify(req.body));
- }
- });
- res.json({ success: true, data: req.body });
-});
-
const server = http.createServer(app);
// 在HTTP服务器上初始化WebSocket服务器
const wss = new Server({ server });
wss.on("connection", ws => {
console.log("Client connected");
- ws.send("Welcome to the WebSocket server!");
- ws.on("message", message => {
- console.log(`Received message: ${message}`);
- // 广播收到的消息给所有连接的客户端
- wss.clients.forEach(client => {
- if (client.readyState === ws.OPEN) {
- client.send(message.toString());
- }
- });
- });
+ // ws.send("Welcome to the WebSocket server!");
+ // ws.on("message", message => {
+ // console.log(`Received message: ${message}`);
+ // // 广播收到的消息给所有连接的客户端
+ // wss.clients.forEach(client => {
+ // if (client.readyState === ws.OPEN) {
+ // client.send(message.toString());
+ // }
+ // });
+ // });
// 当连接关闭时触发
+ ws.send(JSON.stringify(getCurrStatus()));
ws.on("close", () => {
console.log("Client disconnected");
});
});
-
+function getCurrStatus() {
+ return app.locals["status"] as StatusDatagram["data"];
+}
app.locals["wss"] = wss;
+app.locals["status"] = defaultStatus;
+
+// app.get("/", (req, res) => {
+// res.send("Hello World!");
+// });
+app.use("/api/debug", debugRouter);
+app.use("/api/cmd", cmdRouter);
+
+//@ts-ignore
+app.use((err, req, res, next) => {
+ console.error(err.stack);
+ res.status(500).send("Something broke!");
+});
// 监听端口
const PORT = process.env.PORT || 3003;
diff --git a/src/middlewares/auth.ts b/src/middlewares/auth.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/middlewares/logger.ts b/src/middlewares/logger.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/models/User.ts b/src/models/User.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/routes/cmd.ts b/src/routes/cmd.ts
new file mode 100644
index 0000000..6f6288f
--- /dev/null
+++ b/src/routes/cmd.ts
@@ -0,0 +1,20 @@
+import express from "express";
+import { delay } from "../utils/helper";
+import { wsSend } from "../utils/wss";
+const router = express.Router();
+
+router.post("/", async (req, res) => {
+ await delay(200);
+ setTimeout(() => {
+ wsSend(req.app.locals["wss"], {
+ type: "cmd",
+ data: {
+ commandId: req.body.commandId,
+ status: "D0000",
+ },
+ });
+ }, 2000);
+ res.json({ code: "00000", msg: "执行成功" });
+});
+
+export default router;
diff --git a/src/routes/debug.ts b/src/routes/debug.ts
new file mode 100644
index 0000000..9f6e4a1
--- /dev/null
+++ b/src/routes/debug.ts
@@ -0,0 +1,23 @@
+import express from "express";
+import { delay } from "../utils/helper";
+import { wsSend } from "../utils/wss";
+import { StatusDatagram } from "../types/wsTypes";
+const router = express.Router();
+
+router.post("/railArm", async (req, res) => {
+ // await delay(200);
+ const curr: StatusDatagram["data"] = req.app.locals["status"];
+ setTimeout(() => {
+ curr.railArm.x = req.body.x;
+ curr.railArm.y = req.body.y;
+ curr.railArm.z = req.body.z;
+ wsSend(req.app.locals["wss"], {
+ type: "status",
+ data: curr,
+ });
+ }, 1000);
+
+ res.json({ code: "00000", msg: "执行成功" });
+});
+
+export default router;
diff --git a/src/types/cmdTypes.ts b/src/types/cmdTypes.ts
new file mode 100644
index 0000000..a307a09
--- /dev/null
+++ b/src/types/cmdTypes.ts
@@ -0,0 +1,142 @@
+
+type UpTrayStepStruct = {
+ method: "upTray";
+ // params: {
+ // heaterId: number;
+ // };
+};
+type DownTrayStepStruct = {
+ method: "downTray";
+ // params: {
+ // heaterId: number;
+ // };
+};
+export type TubeSolStruct = {
+ tubeNum: number;
+ addLiquidList: Array<{
+ solId: number;
+ volume: number;
+ }>;
+};
+type AddLiquidStepStruct = {
+ method: "addLiquid";
+ params: {
+ solId: number;
+ volume: number;
+ tubeSolList?: TubeSolStruct[];
+ };
+};
+type MoveToSolStepStruct = {
+ method: "moveToSol";
+ // params: {
+ // heaterId: number;
+ // };
+};
+type MoveToHeaterStepStruct = {
+ method: "moveToHeat";
+ // params: {
+ // heaterId: number;
+ // };
+};
+type ShakingStepStruct = {
+ method: "shaking";
+ params: {
+ second: number;
+ };
+};
+
+type StartHeatingStepStruct = {
+ method: "startHeating";
+ params: {
+ // heaterId: number;
+ temperature: number;
+ };
+};
+type StopHeatingStepStruct = {
+ method: "stopHeating";
+ // params: {
+ // heaterId: number;
+ // };
+};
+type TakePhotoStepStruct = {
+ method: "takePhoto";
+};
+type DelayStepStruct = {
+ method: "delay";
+ params: {
+ second: number;
+ };
+};
+
+export type StepStruct =
+ | UpTrayStepStruct
+ | DownTrayStepStruct
+ | AddLiquidStepStruct
+ | MoveToSolStepStruct
+ | MoveToHeaterStepStruct
+ | ShakingStepStruct
+ | StartHeatingStepStruct
+ | StopHeatingStepStruct
+ | TakePhotoStepStruct
+ | DelayStepStruct;
+
+export type StepCmd = StepStruct["method"];
+
+export const StepCmdDescMap: { [k in StepCmd]: string } = {
+ upTray: "抬起托盘",
+ downTray: "降下托盘",
+ addLiquid: "添加溶液",
+ moveToSol: "移至加液",
+ moveToHeat: "移至加热",
+ shaking: "摇匀",
+ startHeating: "开始加热",
+ stopHeating: "停止加热",
+ takePhoto: "拍照",
+ delay: "等待",
+};
+
+export const CmdDescMap: { [k in OperationCmd]: string } = {
+ upTray: "抬起托盘",
+ downTray: "降下托盘",
+ injectFluid: "注入溶液",
+ moveToActionArea: "移至操作区",
+ startShakeUp: "开始摇匀",
+ stopShakeUp: "结束摇匀",
+ startHeat: "开始加热",
+ stopHeat: "停止加热",
+ // keepHeat: "恒温",
+ takePhoto: "拍照",
+ // moveToUnusual: "移至异常区",
+ moveToHeatArea: "移至加热区",
+ takeOffCap: "取下拍子",
+ putBackCap: "装回拍子",
+ openClaw: "张开夹爪",
+ closeClaw: "收合夹爪",
+ moveMachineArm: "移动机械臂",
+ moveTube: "移动试管",
+ openDoor: "开门",
+ closeDoor: "关门",
+
+};
+
+export type OperationCmd =
+ | "upTray" // 抬起托盘
+ | "downTray" // 降下托盘
+ | "injectFluid" // 注入溶液
+ | "moveToActionArea" // 移至操作区
+ | "startShakeUp" // 开始摇匀
+ | "stopShakeUp" // 结束摇匀
+ | "startHeat" // 开始加热
+ | "stopHeat" // 停止加热
+ // | "keepHeat" // 恒温
+ | "takePhoto" // 拍照
+ // | "moveToUnusual" // 移至异常区
+ | "moveToHeatArea" // 移至加热区
+ | "takeOffCap" // 取下拍子
+ | "putBackCap" // 装回拍子
+ | "openClaw" // 张开夹爪
+ | "closeClaw" // 收合夹爪
+ | "moveMachineArm" // 移动机械臂
+ | "moveTube" // 移动试管
+ | "openDoor" //开门
+ | "closeDoor"; //关门
diff --git a/src/types/wsTypes.ts b/src/types/wsTypes.ts
new file mode 100644
index 0000000..cfef079
--- /dev/null
+++ b/src/types/wsTypes.ts
@@ -0,0 +1,266 @@
+import type { StepCmd } from "./cmdTypes";
+
+export type CmdDatagram = {
+ type: "cmd"; // 指令
+ data: {
+ commandId: string;
+ // commandName: DebugCmd;
+ status: "D0000" | "D1111";
+ message?: string;
+ // success: boolean;
+ };
+};
+
+export type CraftDatagram = {
+ type: "crafts";
+ data: {
+ // 当前工艺执行状态,0 表示未执行,1 表示正在执行,2 表示暂停执行,3 表示停止执行 4:Error, 6: 完成。
+ status: 0 | 1 | 2 | 3 | 4 | 6;
+ // 当前正在执行的具体工艺方法
+ method: StepCmd;
+ // 当前正在执行的工艺步骤索引
+ methodIndex: number;
+ // 加热区 ID
+ heatId: number;
+ };
+};
+
+export type WarnDatagram = {
+ type: "warn"; // 报警
+ data: {
+ code: string;
+ msg: string;
+ module: string;
+ };
+};
+
+export type StatusDatagram = {
+ type: "status"; // 状态
+ data: {
+ emergencyStop: boolean; // 硬件急停信号,true 为急停触发,false 为正常运行
+ doorStatus: boolean; // 门的状态,false 表示关闭,true 表示开启
+ railArm: {
+ x: number;
+ y: number;
+ z: number;
+ joint1: number;
+ joint2: number;
+ distance: number; // 当前机械臂(轴 3)上下移动的距离
+ railDistance: number;
+ clawDistance: number;
+ clawStatus: boolean; // 夹爪状态,true 为张开,false 为闭合
+ isZeroPos: boolean; // 导轨是否在原点
+ isLimitPos: boolean; // 导轨是否在限位点
+ };
+ // 操作区(加液、摇匀、拍照)状态
+ liquidArea: {
+ liquidArm: {
+ x: number;
+ y: number;
+ z: number;
+ joint1: number;
+ joint2: number;
+ pump: Array<{
+ pumpId: number;
+ isPumping: boolean; // 是否正在加液,true正在加液
+ }>;
+ };
+ isShaking: boolean; // 是否正在摇匀
+ liquidTray: boolean; // 是否存在托盘
+ // 溶液容器状态
+ solutionBucket: Array<{
+ isEmpty: boolean; // 容器是否为空
+ isFull: boolean; // 容器是否已满
+ }>;
+ };
+
+ // 加热区列表
+ heatArea: Array<{
+ // heaterId: string;
+ hardwareId: string;
+ trayStatus: 0 | 1 | 2; // 0为无托盘,1为有托盘,2为托盘抬起
+ isHeating: boolean; // 是否正在加热
+ capStatus: boolean; // 是否存在拍子
+ isSealed: boolean; // 拍子密封状态,true为已密封,false为未密封
+ temperature: number; // 当前温度
+ }>;
+ // 碱容器状态(废液桶)
+ alkaliBucket: {
+ isEmpty: boolean; // 容器是否为空
+ isFull: boolean; // 容器是否已满
+ };
+ };
+};
+
+export type CraftState = {
+ type: "crafts";
+ data: {
+ heatId: string | number;
+ methodIndex: string | number;
+ status: string | number;
+ };
+};
+
+export type ContainerDatagram = {
+ type: "container";
+ data: {
+ containerList: Array<{
+ id: number;
+ type: 0 | 1; // 0:酸液 1:废液
+ solutionId: number;
+ pumpId: number;
+ capacityTotal: number;
+ capacityUsed: number;
+ }>;
+ };
+};
+
+export type Datagram = CmdDatagram | WarnDatagram | StatusDatagram | CraftDatagram | ContainerDatagram;
+
+export const defaultStatus: StatusDatagram["data"] = {
+ emergencyStop: false, // 硬件急停信号,true 为急停触发,false 为正常运行
+ doorStatus: false, // 门的状态,false 表示关闭,true 表示开启
+ railArm: {
+ x: 0,
+ y: 0,
+ z: 0,
+ joint1: 0,
+ joint2: 0,
+ distance: 0, // 当前机械臂(轴 3)上下移动的距离
+ railDistance: 0,
+ clawDistance: 0,
+ clawStatus: false, // 夹爪状态,true 为张开,false 为闭合
+ isZeroPos: true, // 导轨是否在原点
+ isLimitPos: false, // 导轨是否在限位点
+ },
+ // 操作区(加液、摇匀、拍照)状态
+ liquidArea: {
+ liquidArm: {
+ x: 0,
+ y: 0,
+ z: 0,
+ joint1: 0,
+ joint2: 0,
+ pump: [
+ {
+ pumpId: 1,
+ isPumping: false, // 是否正在加液,true正在加液
+ },
+ {
+ pumpId: 2,
+ isPumping: false, // 是否正在加液,true正在加液
+ },
+ {
+ pumpId: 3,
+ isPumping: false, // 是否正在加液,true正在加液
+ },
+ {
+ pumpId: 4,
+ isPumping: false, // 是否正在加液,true正在加液
+ },
+ {
+ pumpId: 5,
+ isPumping: false, // 是否正在加液,true正在加液
+ },
+ {
+ pumpId: 6,
+ isPumping: false, // 是否正在加液,true正在加液
+ },
+ ],
+ },
+ isShaking: false, // 是否正在摇匀
+ liquidTray: false, // 是否存在托盘
+ // 溶液容器状态
+ solutionBucket: [
+ {
+ isEmpty: false, // 容器是否为空
+ isFull: false, // 容器是否已满
+ },
+ {
+ isEmpty: false, // 容器是否为空
+ isFull: false, // 容器是否已满
+ },
+ {
+ isEmpty: false, // 容器是否为空
+ isFull: false, // 容器是否已满
+ },
+ {
+ isEmpty: false, // 容器是否为空
+ isFull: false, // 容器是否已满
+ },
+ {
+ isEmpty: false, // 容器是否为空
+ isFull: false, // 容器是否已满
+ },
+ {
+ isEmpty: false, // 容器是否为空
+ isFull: false, // 容器是否已满
+ },
+ {
+ isEmpty: false, // 容器是否为空
+ isFull: false, // 容器是否已满
+ },
+ {
+ isEmpty: false, // 容器是否为空
+ isFull: false, // 容器是否已满
+ },
+ ],
+ },
+
+ // 加热区列表
+ heatArea: [
+ {
+ hardwareId: "hardware_1",
+ trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
+ isHeating: false, // 是否正在加热
+ capStatus: false, // 是否存在拍子
+ isSealed: false, // 拍子密封状态,true为已密封,false为未密封
+ temperature: 0, // 当前温度
+ },
+ {
+ hardwareId: "hardware_2",
+ trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
+ isHeating: false, // 是否正在加热
+ capStatus: false, // 是否存在拍子
+ isSealed: false, // 拍子密封状态,true为已密封,false为未密封
+ temperature: 0, // 当前温度
+ },
+ {
+ hardwareId: "hardware_3",
+ trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
+ isHeating: false, // 是否正在加热
+ capStatus: false, // 是否存在拍子
+ isSealed: false, // 拍子密封状态,true为已密封,false为未密封
+ temperature: 0, // 当前温度
+ },
+ {
+ hardwareId: "hardware_4",
+ trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
+ isHeating: false, // 是否正在加热
+ capStatus: false, // 是否存在拍子
+ isSealed: false, // 拍子密封状态,true为已密封,false为未密封
+ temperature: 0, // 当前温度
+ },
+ {
+ hardwareId: "hardware_5",
+ trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
+ isHeating: false, // 是否正在加热
+ capStatus: false, // 是否存在拍子
+ isSealed: false, // 拍子密封状态,true为已密封,false为未密封
+ temperature: 0, // 当前温度
+ },
+ {
+ hardwareId: "hardware_6",
+ trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
+ isHeating: false, // 是否正在加热
+ capStatus: false, // 是否存在拍子
+ isSealed: false, // 拍子密封状态,true为已密封,false为未密封
+ temperature: 0, // 当前温度
+ },
+ ],
+ // 碱容器状态(废液桶)
+ alkaliBucket: {
+ isEmpty: false, // 容器是否为空
+ isFull: false, // 容器是否已满
+ },
+};
\ No newline at end of file
diff --git a/src/utils/helper.ts b/src/utils/helper.ts
new file mode 100644
index 0000000..a00a99c
--- /dev/null
+++ b/src/utils/helper.ts
@@ -0,0 +1,7 @@
+export async function delay(mill: number) {
+ return new Promise(resolve => {
+ setTimeout(() => {
+ resolve({});
+ }, mill);
+ });
+}
diff --git a/src/utils/wss.ts b/src/utils/wss.ts
new file mode 100644
index 0000000..8181483
--- /dev/null
+++ b/src/utils/wss.ts
@@ -0,0 +1,11 @@
+import { Server } from "ws";
+import { Datagram } from "../types/wsTypes";
+
+export function wsSend(wss: Server, data: Datagram) {
+ // 广播消息给所有连接的客户端
+ wss.clients.forEach(client => {
+ if (client.readyState === client.OPEN) {
+ client.send(JSON.stringify(data));
+ }
+ });
+}
+ x
+
+ y
+
+ z
+
+