From 98eae5e0507f71c7ea1eebdc3175b58d6b8d7fdf Mon Sep 17 00:00:00 2001 From: orisys Date: Sat, 25 Jul 2026 14:43:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=E3=80=8Cbash=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bash/no-overview-at-startup.sh | 13 ++ bash/run_gripper.sh | 243 +++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 bash/no-overview-at-startup.sh create mode 100644 bash/run_gripper.sh diff --git a/bash/no-overview-at-startup.sh b/bash/no-overview-at-startup.sh new file mode 100644 index 0000000..07ead5f --- /dev/null +++ b/bash/no-overview-at-startup.sh @@ -0,0 +1,13 @@ +#!/usr/bin/bash +# 监控时间,50 * 0.1秒 = 5秒 +MTIME=50 +for ((i=0; i<${MTIME}; i++)); do + # 查询当前是否处于概览模式 + read -r DUMMY DUMMY IS_OVERVIEW <<< "$(dbus-send --print-reply=literal --session --dest=org.gnome.Shell --type=method_call /org/gnome/Shell org.freedesktop.DBus.Properties.Get string:org.gnome.Shell string:OverviewActive)" + if [[ "${IS_OVERVIEW}" = "true" ]] ; then + # 如果处于概览模式,发送命令关闭它 + /usr/bin/dbus-send --session --dest=org.gnome.Shell --type=method_call /org/gnome/Shell org.freedesktop.DBus.Properties.Set string:org.gnome.Shell string:OverviewActive variant:boolean:false + exit + fi + sleep 0.1 +done diff --git a/bash/run_gripper.sh b/bash/run_gripper.sh new file mode 100644 index 0000000..16f8d11 --- /dev/null +++ b/bash/run_gripper.sh @@ -0,0 +1,243 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# ============================================ +# 配置项 +# ============================================ +PROJECT_DIR="${PROJECT_DIR:-$HOME/release/ctag2f-90d-sdk}" +WARMUP_DIR="${WARMUP_DIR:-$HOME/release/orisys-sdk}" +CONDA_ENV="${CONDA_ENV:-py311}" +RENDER_MODE="${RENDER_MODE:-auto}" +GRIPPER_CONFIG="${GRIPPER_CONFIG:-$PROJECT_DIR/config/gripper.json}" + +# ============================================ +# 检测 USB 摄像头并返回主设备索引(整数) +# ============================================ +detect_cameras() { + declare -A cam_nodes + declare -A cam_paths + + for dev in /dev/video*; do + [[ -e "$dev" ]] || continue + local dev_num="${dev##*/video}" + local info + info=$(udevadm info -n "$dev" 2>/dev/null || true) + + # 检查是否为 USB 摄像头(根据 ID_MODEL 或 ID_VENDOR) + if echo "$info" | grep -qi "ID_MODEL.*USB Camera" || \ + echo "$info" | grep -qi "ID_VENDOR.*1bcf" ; then + local id_path + id_path=$(echo "$info" | grep -i "ID_PATH=" | cut -d'=' -f2 || true) + if [[ -z "$id_path" ]]; then + id_path=$(udevadm info -q path -n "$dev" 2>/dev/null || true) + fi + local key="$id_path" + if [[ -z "${cam_nodes[$key]:-}" ]]; then + cam_nodes[$key]="$dev_num" + else + local current="${cam_nodes[$key]}" + if (( dev_num < current )); then + cam_nodes[$key]="$dev_num" + fi + fi + cam_paths[$key]="$id_path" + fi + done + + if [[ ${#cam_nodes[@]} -lt 2 ]]; then + echo "错误:找到 ${#cam_nodes[@]} 个 USB 摄像头,需要 2 个。" >&2 + return 1 + fi + + local cam_left="" + local cam_right="" + for key in "${!cam_nodes[@]}"; do + local path="$key" + local num="${cam_nodes[$key]}" + if [[ "$path" == *"xhci-hcd.0"* ]] || [[ "$path" == *"usb1"* ]]; then + cam_left="$num" + elif [[ "$path" == *"xhci-hcd.1"* ]] || [[ "$path" == *"usb2"* ]]; then + cam_right="$num" + else + if [[ -z "$cam_left" ]] || (( num < cam_left )); then + cam_right="$cam_left" + cam_left="$num" + else + cam_right="$num" + fi + fi + done + + if [[ -z "$cam_left" ]] || [[ -z "$cam_right" ]]; then + local nums=() + for n in "${cam_nodes[@]}"; do nums+=("$n"); done + IFS=$'\n' sorted=($(sort -n <<<"${nums[*]}")) + cam_left="${sorted[0]}" + cam_right="${sorted[1]}" + fi + + echo "$cam_left $cam_right" +} + +# ============================================ +# 更新 gripper.json 中的 video 路径 +# ============================================ +update_config() { + local cam_left_idx="$1" + local cam_right_idx="$2" + local config_file="$GRIPPER_CONFIG" + + # 检查 jq 是否安装 + if ! command -v jq &> /dev/null; then + echo "jq 未安装,正在安装..." + sudo apt update && sudo apt install -y jq + fi + + # 构建设备路径 + local video1="/dev/video$cam_left_idx" + local video2="/dev/video$cam_right_idx" + + echo "更新配置文件: $config_file" + echo " video1 = $video1" + echo " video2 = $video2" + + # 使用 jq 更新字段 + jq --arg v1 "$video1" --arg v2 "$video2" \ + '.video1 = $v1 | .video2 = $v2' "$config_file" > "$config_file.tmp" + mv "$config_file.tmp" "$config_file" + echo "✅ 配置文件已更新。" +} + +# ============================================ +# 加载 conda 环境 +# ============================================ +load_conda() { + for conda_sh in \ + "$HOME/miniconda3/etc/profile.d/conda.sh" \ + "$HOME/anaconda3/etc/profile.d/conda.sh" \ + "/opt/conda/etc/profile.d/conda.sh"; do + if [[ -f "$conda_sh" ]]; then + # shellcheck disable=SC1090 + source "$conda_sh" + break + fi + done + + if ! command -v conda >/dev/null 2>&1; then + echo "Conda not found." >&2 + exit 1 + fi + + conda activate "$CONDA_ENV" + echo "✅ Conda environment '$CONDA_ENV' activated." +} + +# ============================================ +# 主逻辑 +# ============================================ +main() { + # 检查项目目录 + if [[ ! -d "$PROJECT_DIR" ]]; then + echo "错误:项目目录不存在: $PROJECT_DIR" >&2 + exit 1 + fi + if [[ ! -d "$WARMUP_DIR" ]]; then + echo "警告:warmup 目录不存在: $WARMUP_DIR,跳过预热。" >&2 + WARMUP_DIR="" + fi + + load_conda + + # 移除不兼容的 PyOpenGL-accelerate + if python -c 'import OpenGL_accelerate' >/dev/null 2>&1; then + echo "移除不兼容的 PyOpenGL-accelerate ..." + python -m pip uninstall -y PyOpenGL-accelerate + fi + + # 检测摄像头 + echo "正在检测 USB 摄像头..." + CAMERAS=$(detect_cameras) + if [[ -z "$CAMERAS" ]]; then + echo "错误:无法检测到两个 USB 摄像头。" >&2 + exit 1 + fi + CAM_LEFT=$(echo "$CAMERAS" | awk '{print $1}') + CAM_RIGHT=$(echo "$CAMERAS" | awk '{print $2}') + echo "左摄像头索引: $CAM_LEFT" + echo "右摄像头索引: $CAM_RIGHT" + + # --- 更新配置文件 --- + update_config "$CAM_LEFT" "$CAM_RIGHT" + + # ---------- 执行 warmup ---------- + if [[ -n "$WARMUP_DIR" ]]; then + echo "=============================================" + echo "🧪 开始传感器预热 (sensor warmup)" + echo " 目录: $WARMUP_DIR" + echo "=============================================" + cd "$WARMUP_DIR" + + echo ">>> 执行: python warmup.py -v $CAM_LEFT" + python warmup.py -v "$CAM_LEFT" + echo "✅ warmup 左摄像头完成" + + echo ">>> 执行: python warmup.py -v $CAM_RIGHT" + python warmup.py -v "$CAM_RIGHT" + echo "✅ warmup 右摄像头完成" + + cd "$PROJECT_DIR" + echo "=============================================" + echo "✅ 传感器预热全部完成" + echo "=============================================" + fi + + # ---------- 设置渲染模式 ---------- + if [[ "$RENDER_MODE" == "auto" ]]; then + wayland_plugin="$(find "${CONDA_PREFIX:-/nonexistent}" -type f \ + -path '*/platforms/libqwayland*.so' -print -quit 2>/dev/null || true)" + if [[ -n "$wayland_plugin" && -n "${WAYLAND_DISPLAY:-}" ]]; then + RENDER_MODE=wayland + else + echo "Conda Qt 没有 Wayland 插件;使用 XWayland 和软件 OpenGL。" + RENDER_MODE=software + fi + fi + + case "$RENDER_MODE" in + wayland) + if [[ -z "${WAYLAND_DISPLAY:-}" ]]; then + echo "WAYLAND_DISPLAY 为空。请在 Ubuntu 桌面终端中运行此脚本。" >&2 + exit 1 + fi + export QT_QPA_PLATFORM=wayland + export PYOPENGL_PLATFORM=egl + unset QT_OPENGL LIBGL_ALWAYS_SOFTWARE QT_XCB_GL_INTEGRATION + ;; + software) + export QT_QPA_PLATFORM=xcb + export QT_OPENGL=software + export LIBGL_ALWAYS_SOFTWARE=1 + export PYOPENGL_PLATFORM=glx + export QT_XCB_GL_INTEGRATION=xcb_glx + ;; + xcb) + export QT_QPA_PLATFORM=xcb + export PYOPENGL_PLATFORM=glx + export QT_XCB_GL_INTEGRATION=xcb_glx + unset QT_OPENGL LIBGL_ALWAYS_SOFTWARE + ;; + *) + echo "未知的 RENDER_MODE: $RENDER_MODE (可用: auto, wayland, software, xcb)" >&2 + exit 2 + ;; + esac + + # ---------- 启动主程序 ---------- + echo "🚀 启动 gripper visualizer: mode=$RENDER_MODE, conda=$CONDA_ENV" + exec python -m gripper.visualizer "$@" +} + +# ============================================ +# 执行主函数 +# ============================================ +main "$@"