Node.js调用Python YOLO进程未执行相机移动及休眠问题排查
Node.js调用YOLO控制相机异常问题排查与解决
问题描述
我想用Node.js调用Python的YOLO完成人体检测,拿到人体坐标后控制相机移动。已经写了用spawn启动Python进程的代码,也实现了监听stderr处理坐标、控制相机的逻辑,但目前进程持续接收数据,相机移动和休眠功能均未执行,无法定位问题。
相关代码
Node.js进程启动代码
const yoloProcess = spawn( "C:\\Users\\LAB908\\anaconda3\\envs\\yolov5\\python", [ "C:\\Users\\LAB908\\Downloads\\yolov5-deepsparse-blogpost-main\\yolov5-train\\detect.py", "--class", "0", "--weights", "yolov5s.pt", "--source", "rtsp://admin:123456@169.254.10.100/stream0", ], { encoding: "utf8", } );
Node.js坐标处理与相机控制逻辑
var i = 1; yoloProcess.stderr.on("data", async (data) => { left = data.toString().split(",")[0].replace("(", ""); right = data.toString().replace(")", "").replace("\n", "").split(",")[1]; //console.log(data.toString()); console.log("left:" + String(left)); console.log("right:" + String(right)); await sleep(3000); pos.push((parseFloat(right) + parseFloat(left)) / 2); console.log(pos); if (pos[i] - pos[i - 1] > 0) { await move_right(); console.log("move right"); } else if (pos[i] - pos[i - 1] < 0) { await move_left(); console.log("move left"); } else { await move_stop(); console.log("do not move"); } });
问题根源分析
- 异步回调并发冲突:
stderr.on("data")会被YOLO的高频帧输出持续触发,每个回调都是异步执行。await sleep(3000)仅阻塞当前回调,但新的data事件会立刻启动新的回调,导致多个控制逻辑同时运行,相机指令被打乱,休眠效果也被并发回调抵消。 - 数据解析不可靠:直接按逗号分割
data的方式未做过滤,YOLO的stderr会输出初始化日志、帧率信息等非坐标内容,分割后得到的left/right可能是无效字符串,后续数值计算出错,相机控制逻辑无法进入正确分支。 - 索引逻辑错误:初始
i=1,但pos数组为空,第一次push后数组长度为1,pos[i]即pos[1]为undefined,差值计算结果为NaN,所有条件判断都不成立,相机控制代码完全未执行。
修复方案
1. 限制回调并发,实现帧过滤
通过标记位控制同一时间仅处理一组坐标,避免回调堆积,同时只处理有效坐标:
let isProcessing = false; let latestCoords = null; const pos = []; // 确保pos已初始化 yoloProcess.stderr.on("data", (data) => { const rawStr = data.toString().trim(); // 仅处理符合"(x,y)"格式的行 if (rawStr.startsWith("(") && rawStr.endsWith(")")) { const [leftStr, rightStr] = rawStr.replace(/[()]/g, "").split(","); const left = parseFloat(leftStr); const right = parseFloat(rightStr); if (!isNaN(left) && !isNaN(right)) { latestCoords = { left, right }; } } // 当前无处理任务时,启动坐标处理流程 if (!isProcessing && latestCoords) { isProcessing = true; processCoords(latestCoords).finally(() => { isProcessing = false; latestCoords = null; }); } }); async function processCoords(coords) { const { left, right } = coords; console.log(`left: ${left}, right: ${right}`); await sleep(3000); const center = (left + right) / 2; pos.push(center); console.log(pos); // 数组至少有2个元素再做移动判断 if (pos.length >= 2) { const diff = pos[pos.length - 1] - pos[pos.length - 2]; if (diff > 0) { await move_right(); console.log("move right"); } else if (diff < 0) { await move_left(); console.log("move left"); } else { await move_stop(); console.log("do not move"); } } else { await move_stop(); console.log("initial position, stop moving"); } }
2. 优化YOLO输出格式(更可靠)
修改YOLO的detect.py,让它仅将有效人体坐标以JSON格式输出到stdout,避免和日志混在一起:
# 在detect.py的检测循环中添加以下代码(找到处理检测结果的位置) import json for *xyxy, conf, cls in reversed(det): if int(cls) == 0: # 仅处理人体类(class 0) x1, x2 = xyxy[0], xyxy[2] # 取bbox的左右x坐标 # 打印JSON并强制刷新缓冲区,确保Node.js能实时接收 print(json.dumps({"left": float(x1), "right": float(x2)}), flush=True)
然后Node.js改为监听stdout:
yoloProcess.stdout.on("data", (data) => { const lines = data.toString().split("\n").filter(line => line.trim()); for (const line of lines) { try { const coords = JSON.parse(line); latestCoords = coords; } catch (e) { // 跳过无效JSON行 continue; } } // 后续处理逻辑同方案1 });
3. 修复坐标比较逻辑
移除固定索引i,直接通过数组长度获取最后两个元素的差值,彻底避免索引越界问题:
// 替换原有的差值判断逻辑 if (pos.length >= 2) { const diff = pos[pos.length - 1] - pos[pos.length - 2]; // 后续移动判断逻辑不变 }
内容的提问来源于stack exchange,提问作者chi peitzu
相关产品推荐
相关产品推荐

