feat: monitor robot moving
This commit is contained in:
parent
d6c15c2235
commit
224b7e3cbf
45
README.md
45
README.md
@ -1,9 +1,11 @@
|
||||
# 页面路由
|
||||
|
||||
1. 场景编辑
|
||||
/scene-editor/:id 【id为场景id】
|
||||
/scene-editor/:id [id为场景id]
|
||||
2. 组编辑
|
||||
/group-editor/:sid/:id 【sid为场景id,id为机器人组id】
|
||||
/group-editor/:sid/:id [sid为场景id,id为机器人组id]
|
||||
3. 运行监控
|
||||
/movement-supervision/:sid [sid为场景id]
|
||||
|
||||
# 场景接口
|
||||
|
||||
@ -113,6 +115,38 @@ POST /scene/saveByGroupId
|
||||
响应体:
|
||||
无
|
||||
|
||||
## 实时监控场景
|
||||
|
||||
WebSocket /scene/monitor/:id [id为场景id]
|
||||
|
||||
实时数据:
|
||||
RobotRealtimeInfo [JSON]
|
||||
|
||||
示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "mock-robot-1",
|
||||
"label": "模拟机器人A",
|
||||
"brand": "模拟品牌A",
|
||||
"type": 1,
|
||||
"ip": "127.0.1.1",
|
||||
"isConnected": true,
|
||||
"state": 4,
|
||||
"canOrder": true,
|
||||
"canStop": true,
|
||||
"canControl": true,
|
||||
"x": 800,
|
||||
"y": 500,
|
||||
"active": true,
|
||||
"angle": -90,
|
||||
"path": [
|
||||
[600, 500],
|
||||
[100, 400]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
# 机器人接口
|
||||
|
||||
## 获取所有机器人
|
||||
@ -354,6 +388,13 @@ export interface RobotDetail extends RobotInfo {
|
||||
taskBattery?: number; // 任务电量
|
||||
swapBattery?: number; // 交换电量
|
||||
}
|
||||
export interface RobotRealtimeInfo extends RobotInfo {
|
||||
x: number; // 坐标x
|
||||
y: number; // 坐标y
|
||||
active?: boolean; // 是否运行
|
||||
angle?: number; // 旋转角度
|
||||
path?: Array<[number, number]>; // 规划路径
|
||||
}
|
||||
|
||||
enum RobotBrand {
|
||||
'先工' = 1,
|
||||
|
@ -21,11 +21,7 @@ const points = computed<MapPen[]>(() =>
|
||||
|
||||
//#region 线路列表
|
||||
const routes = computed<MapPen[]>(() =>
|
||||
editor.value.routes.value.filter(({ label }) => {
|
||||
console.log(label);
|
||||
|
||||
return label?.includes(keyword.value);
|
||||
}),
|
||||
editor.value.routes.value.filter(({ label }) => label?.includes(keyword.value)),
|
||||
);
|
||||
//#endregion
|
||||
|
||||
|
@ -195,5 +195,10 @@ const selectRobot = (id: string) => {
|
||||
width: 320px;
|
||||
height: calc(100% - 96px);
|
||||
overflow: visible;
|
||||
pointer-events: none;
|
||||
|
||||
& > * {
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -57,10 +57,10 @@ onMounted(async () => {
|
||||
let x = 800;
|
||||
let y = 500;
|
||||
const active = true;
|
||||
const angle = 0;
|
||||
const angle = -90;
|
||||
const path = <[number, number][]>[
|
||||
[600, 500],
|
||||
// [100, 400],
|
||||
[100, 400],
|
||||
];
|
||||
editor.value?.refreshRobot(id, { x, y, active, angle, path });
|
||||
const test = () =>
|
||||
@ -69,7 +69,7 @@ onMounted(async () => {
|
||||
editor.value?.refreshRobot(id, { x, y });
|
||||
test();
|
||||
});
|
||||
// test();
|
||||
test();
|
||||
});
|
||||
onUnmounted(() => {
|
||||
client.value?.close();
|
||||
@ -146,14 +146,6 @@ const selectRobot = (id: string) => {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.toolbar-container {
|
||||
position: fixed;
|
||||
bottom: 40px;
|
||||
left: 50%;
|
||||
z-index: 100;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.card-container {
|
||||
position: fixed;
|
||||
top: 80px;
|
||||
@ -162,5 +154,10 @@ const selectRobot = (id: string) => {
|
||||
width: 320px;
|
||||
height: calc(100% - 96px);
|
||||
overflow: visible;
|
||||
pointer-events: none;
|
||||
|
||||
& > * {
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -195,5 +195,10 @@ const selectRobot = (id: string) => {
|
||||
width: 320px;
|
||||
height: calc(100% - 96px);
|
||||
overflow: visible;
|
||||
pointer-events: none;
|
||||
|
||||
& > * {
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -374,12 +374,16 @@ export class EditorService extends Meta2d {
|
||||
}
|
||||
|
||||
public refreshRobot(id: RobotInfo['id'], info: Partial<RobotRealtimeInfo>): void {
|
||||
const { rotate: or, robot } = this.getPenById(id) ?? {};
|
||||
const pen = this.getPenById(id);
|
||||
const { rotate: or, robot } = pen ?? {};
|
||||
if (!robot?.type) return;
|
||||
const { x: ex = 37, y: ey = 37, active, angle, path } = info;
|
||||
const x = ex - 37;
|
||||
const y = ey - 37;
|
||||
const { x: ox, y: oy } = this.getPenRect(pen!);
|
||||
const { x: cx = 37, y: cy = 37, active, angle, path: points } = info;
|
||||
const x = cx - 37;
|
||||
const y = cy - 37;
|
||||
const rotate = angle ?? or;
|
||||
const path =
|
||||
points?.map(([px, py]) => [px - cx, py - cy]) ?? robot.path?.map(([ex, ey]) => [ex + ox! - x, ey + oy! - y]);
|
||||
const o = { ...robot, ...omitBy({ active, path }, isNil) };
|
||||
if (isNil(active)) {
|
||||
this.setValue({ id, x, y, rotate, robot: o, visible: true }, { render: true, history: false, doEvent: false });
|
||||
@ -850,41 +854,37 @@ function drawRobot(ctx: CanvasRenderingContext2D, pen: MapPen): void {
|
||||
const { x = 0, y = 0, width: w = 0, height: h = 0, rotate: deg = 0 } = pen.calculative?.worldRect ?? {};
|
||||
const { active, path } = pen.robot ?? {};
|
||||
|
||||
if (!active) return;
|
||||
const ox = x + w / 2;
|
||||
const oy = y + h / 2;
|
||||
ctx.save();
|
||||
if (active) {
|
||||
const ox = x + w / 2;
|
||||
const oy = y + h / 2;
|
||||
console.log(ox, oy);
|
||||
|
||||
ctx.ellipse(ox, oy, w / 2, h / 2, 0, 0, Math.PI * 2);
|
||||
ctx.fillStyle = get(theme, 'robot.fill') ?? '';
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = get(theme, 'robot.stroke') ?? '';
|
||||
ctx.ellipse(ox, oy, w / 2, h / 2, 0, 0, Math.PI * 2);
|
||||
ctx.fillStyle = get(theme, 'robot.fill') ?? '';
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = get(theme, 'robot.stroke') ?? '';
|
||||
ctx.stroke();
|
||||
if (path?.length) {
|
||||
ctx.strokeStyle = get(theme, 'robot.line') ?? '';
|
||||
ctx.lineCap = 'round';
|
||||
ctx.lineWidth = s * 4;
|
||||
ctx.setLineDash([s * 5, s * 10]);
|
||||
ctx.translate(ox, oy);
|
||||
ctx.rotate((-deg * Math.PI) / 180);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, 0);
|
||||
path.forEach(([ex, ey]) => ctx.lineTo(ex * s, ey * s));
|
||||
ctx.stroke();
|
||||
if (path?.length) {
|
||||
ctx.strokeStyle = get(theme, 'robot.line') ?? '';
|
||||
ctx.lineCap = 'round';
|
||||
ctx.lineWidth = s * 4;
|
||||
ctx.setLineDash([s * 5, s * 10]);
|
||||
ctx.translate(ox, oy);
|
||||
ctx.rotate((-deg * Math.PI) / 180);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, 0);
|
||||
// todo 缩放时坐标偏移
|
||||
path.forEach(([ex, ey]) => ctx.lineTo((ex - ox) * s, (ey - oy) * s));
|
||||
ctx.stroke();
|
||||
const [x1 = 0, y1 = 0] = nth(path, -1) ?? [];
|
||||
const [x2 = ox, y2 = oy] = nth(path, -2) ?? [];
|
||||
const r = Math.atan2(y1 - y2, x1 - x2) + Math.PI;
|
||||
ctx.setLineDash([0]);
|
||||
ctx.translate((x1 - ox) * s, (y1 - oy) * s);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(Math.cos(r + Math.PI / 4) * s * 10, Math.sin(r + Math.PI / 4) * s * 10);
|
||||
ctx.lineTo(0, 0);
|
||||
ctx.lineTo(Math.cos(r - Math.PI / 4) * s * 10, Math.sin(r - Math.PI / 4) * s * 10);
|
||||
ctx.stroke();
|
||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
}
|
||||
const [ex1 = 0, ey1 = 0] = nth(path, -1) ?? [];
|
||||
const [ex2 = 0, ey2 = 0] = nth(path, -2) ?? [];
|
||||
const r = Math.atan2(ey1 - ey2, ex1 - ex2) + Math.PI;
|
||||
ctx.setLineDash([0]);
|
||||
ctx.translate(ex1 * s, ey1 * s);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(Math.cos(r + Math.PI / 4) * s * 10, Math.sin(r + Math.PI / 4) * s * 10);
|
||||
ctx.lineTo(0, 0);
|
||||
ctx.lineTo(Math.cos(r - Math.PI / 4) * s * 10, Math.sin(r - Math.PI / 4) * s * 10);
|
||||
ctx.stroke();
|
||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user