From e828deb33bb0b29d9d1aba275bdb14b64ea6ca26 Mon Sep 17 00:00:00 2001 From: haotian <2421912570@qq.com> Date: Tue, 30 Sep 2025 17:03:22 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=AE=9E=E7=8E=B0=E4=B8=80?= =?UTF-8?q?=E7=9B=B4=E5=B0=9D=E8=AF=95=E6=89=93=E5=BC=80=E6=91=84=E5=83=8F?= =?UTF-8?q?=E5=A4=B4,=20=E6=9B=B4=E6=96=B0=E8=87=AA=E5=90=AF=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.yaml | 1 + face_rec.py | 37 +++++++++++++++++++------ face_rec.service | 22 ++++++++++----- start.sh | 71 +++++++++++++++++++++++++++++++++++------------- 4 files changed, 96 insertions(+), 35 deletions(-) diff --git a/config.yaml b/config.yaml index 0de4239..cf8e14a 100644 --- a/config.yaml +++ b/config.yaml @@ -20,6 +20,7 @@ camera: width: 1280 height: 720 fps: 30 + retry_interval: 2 # 打开摄像头失败后的重试间隔(秒) # 人脸检测配置 face_detection: diff --git a/face_rec.py b/face_rec.py index 99a7ea6..8d17001 100644 --- a/face_rec.py +++ b/face_rec.py @@ -176,16 +176,35 @@ class FaceRecognitionSystem: def _init_camera(self): """初始化摄像头""" cam_config = self.config['camera'] + retry_interval = cam_config.get('retry_interval', 3) # 默认3秒重试 - self.camera = cv2.VideoCapture(cam_config['device_id']) - self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, cam_config['width']) - self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, cam_config['height']) - self.camera.set(cv2.CAP_PROP_FPS, cam_config['fps']) - - if not self.camera.isOpened(): - raise RuntimeError("无法打开摄像头") - - self.logger.info("摄像头初始化完成") + attempt = 0 + while True: + attempt += 1 + self.logger.info(f"正在尝试打开摄像头 (第{attempt}次尝试)...") + + self.camera = cv2.VideoCapture(cam_config['device_id']) + + if self.camera.isOpened(): + # 设置摄像头参数 + self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, cam_config['width']) + self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, cam_config['height']) + self.camera.set(cv2.CAP_PROP_FPS, cam_config['fps']) + + # 验证是否能读取帧 + ret, frame = self.camera.read() + if ret: + self.logger.info(f"摄像头初始化成功 (设备ID: {cam_config['device_id']})") + return + else: + self.logger.warning("摄像头已打开但无法读取帧") + self.camera.release() + else: + self.logger.warning(f"无法打开摄像头设备 {cam_config['device_id']}") + + # 等待后重试 + self.logger.info(f"{retry_interval}秒后重试...") + time.sleep(retry_interval) def assess_frame_quality(self, frame: np.ndarray) -> float: """评估帧质量(使用Laplacian方差检测模糊度)""" diff --git a/face_rec.service b/face_rec.service index 9b06cc1..cdd49b3 100644 --- a/face_rec.service +++ b/face_rec.service @@ -1,16 +1,24 @@ [Unit] -Description=My Custom Startup Script +Description=Face Rec GUI Service (system-level) +After=display-manager.service +# 或者 After=gdm.service / lightdm.service,根据你系统用的显示管理器 [Service] Type=simple User=unitree -# 配置systemd服务允许访问显示 -Environment="DISPLAY=:1" -Environment="XAUTHORITY=/home/unitree/.Xauthority" -# 这里确保自己对这个脚本有执行权限。现chmod +x xxxx.sh +WorkingDirectory=/home/unitree/robot_face_rec + ExecStart=/home/unitree/robot_face_rec/start.sh Restart=on-failure -WorkingDirectory=/home/unitree/ +RestartSec=5 +TimeoutStartSec=30 + +StandardOutput=journal +StandardError=journal + +# 如果需要,你可以设置环境,但脚本里会重写 DISPLAY +# Environment=DISPLAY=:0 +# Environment=XAUTHORITY=/home/unitree/.Xauthority [Install] -WantedBy=multi-user.target +WantedBy=graphical.target diff --git a/start.sh b/start.sh index cea0223..4b1997d 100755 --- a/start.sh +++ b/start.sh @@ -1,29 +1,62 @@ -#! /bin/bash +#!/bin/bash +# --- 日志相关 --- +LOG_DIR="/home/unitree/robot_face_rec/logs/face_rec" +mkdir -p "$LOG_DIR" +LOG_FILE="$LOG_DIR/face_rec_$(date +%Y%m%d_%H%M%S).log" -# 进入到项目目录 -cd /home/unitree/robot_face_rec +{ + echo "===== $(date) Starting face_rec script =====" + echo "User: $(whoami)" + echo "PWD before cd: $(pwd)" + echo "Python: $(which python) / Version: $(python --version 2>&1)" +} >> "$LOG_FILE" +# 切换到项目目录 +cd /home/unitree/robot_face_rec || { + echo "Failed to cd to project dir" >> "$LOG_FILE" + exit 1 +} -LOG_DIR="logs/face_rec" +{ + echo "PWD after cd: $(pwd)" + echo "Env before display detection: DISPLAY=$DISPLAY, XAUTHORITY=$XAUTHORITY" +} >> "$LOG_FILE" -mkdir -p $LOG_DIR +# --- 动态检测 DISPLAY 的逻辑 --- +# 方法:尝试从正在运行的 Xorg / X 进程环境中读取 DISPLAY -# 生成日志文件名(使用当前时间) -LOG_FILE="$LOG_DIR/robot_$(date +%Y%m%d_%H%M%S).log" +display_found="" -# 检查当前程序是否已经正在运行. +for pid in $(pgrep Xorg); do + if [ -r /proc/$pid/environ ]; then + disp=$(tr '\0' '\n' < /proc/$pid/environ | grep '^DISPLAY=' | cut -d'=' -f2-) + if [ -n "$disp" ]; then + # display_found="$disp" + echo "Chosen " + break + fi + fi +done -if pgrep -f "face_rec.py" > /dev/null; then - echo "face_rec.py 已经在运行中" - exit 1 -fi +# 如果还没找到 DISPLAY,则尝试 fallback +if [ -z "$display_found" ]; then + # 常见默认::0 + display_found=":0" + echo "Chosen default" +fi -# nohup python run_sync_robot.py > "$LOG_FILE" 2>&1 & -# 注systemctl控制时最后的&要去掉,使得脚本一直在运行.脚本其实阻塞在这,后面都不会执行 -nohup python face_rec.py > "$LOG_FILE" 2>&1 +export DISPLAY="$display_found" -# 保存进程id -echo $! > "$LOG_DIR/robot.pid" -echo "WebSocket客户端已启动,日志保存在: $LOG_FILE" -echo "进程ID: $(cat $LOG_DIR/robot.pid)" \ No newline at end of file +{ + echo "Chosen DISPLAY = $DISPLAY" +} >> "$LOG_FILE" + +# XAUTHORITY:假设用户的 .Xauthority 存在于 home 目录 +export XAUTHORITY="/home/unitree/.Xauthority" +{ + echo "Using XAUTHORITY = $XAUTHORITY" +} >> "$LOG_FILE" + +# 最终执行 Python 程序(不后台化,用 exec 替换进程) +exec python face_rec.py >> "$LOG_FILE" 2>&1