[release] 规范 ROS 2 三代目录并校准训练说明
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
# Orin 触控屏控制面板
|
||||
|
||||
`fullscreen_quit.py` 是比赛 Orin 外接 `800×600` 屏幕使用的控制面板,通过本机 `http://127.0.0.1:18080/api/*` 调用 ROS 2 Web bridge,不建立第二套控制协议。
|
||||
|
||||
```bash
|
||||
cd <sim2real_ros2_v3工作区>
|
||||
DISPLAY=:0 python3 screen/fullscreen_quit.py
|
||||
```
|
||||
|
||||
程序默认从脚本父目录自动确定工作区,也可设置 `SIM2REAL_REPO_DIR` 覆盖。显示权限检查:
|
||||
|
||||
```bash
|
||||
python3 screen/check_display.py
|
||||
```
|
||||
|
||||
自启动脚本:
|
||||
|
||||
- `install_autostart.sh`:图形桌面登录后启动。
|
||||
- `install_boot_service.sh <用户名>`:安装 systemd 服务。
|
||||
- `uninstall_boot_service.sh`:卸载服务。
|
||||
|
||||
使用屏幕启动系统前,先完成工作区构建、Odin 配置、CAN 映射检查和急停验证。
|
||||
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Print display-related diagnostics for launching the fullscreen quit screen.
|
||||
"""
|
||||
|
||||
import glob
|
||||
import getpass
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
def run(command: List[str]) -> str:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
command,
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
except OSError as exc:
|
||||
return f"<failed: {exc}>"
|
||||
|
||||
output = result.stdout.strip()
|
||||
error = result.stderr.strip()
|
||||
if error:
|
||||
return f"{output}\n{error}".strip()
|
||||
return output
|
||||
|
||||
|
||||
def current_user() -> str:
|
||||
try:
|
||||
return getpass.getuser()
|
||||
except OSError:
|
||||
return os.environ.get("USER", "unknown")
|
||||
|
||||
|
||||
def xauth_from_x_processes() -> List[str]:
|
||||
output = run(["ps", "-eo", "args"])
|
||||
candidates = []
|
||||
for line in output.splitlines():
|
||||
if "Xorg" not in line and "Xwayland" not in line:
|
||||
continue
|
||||
try:
|
||||
parts = shlex.split(line)
|
||||
except ValueError:
|
||||
parts = line.split()
|
||||
for index, part in enumerate(parts[:-1]):
|
||||
if part == "-auth":
|
||||
candidates.append(parts[index + 1])
|
||||
return candidates
|
||||
|
||||
|
||||
def print_path_status(label: str, path: Optional[str]) -> None:
|
||||
if not path:
|
||||
print(f"{label}: <unset>")
|
||||
return
|
||||
exists = os.path.exists(path)
|
||||
readable = os.access(path, os.R_OK) if exists else False
|
||||
print(f"{label}: {path} exists={exists} readable={readable}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
uid = os.getuid()
|
||||
print(f"user: {run(['whoami'])}")
|
||||
print(f"uid: {uid}")
|
||||
print(f"DISPLAY: {os.environ.get('DISPLAY', '<unset>')}")
|
||||
print(f"XAUTHORITY: {os.environ.get('XAUTHORITY', '<unset>')}")
|
||||
print()
|
||||
|
||||
print("candidate XAUTHORITY files:")
|
||||
candidates = [
|
||||
os.environ.get("XAUTHORITY"),
|
||||
*xauth_from_x_processes(),
|
||||
os.path.expanduser("~/.Xauthority"),
|
||||
f"/run/user/{uid}/gdm/Xauthority",
|
||||
f"/run/user/{uid}/Xauthority",
|
||||
*glob.glob(f"/run/user/{uid}/*Xauthority*"),
|
||||
]
|
||||
|
||||
seen = set()
|
||||
for candidate in candidates:
|
||||
key = candidate or "<unset>"
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
print_path_status(" -", candidate)
|
||||
|
||||
print()
|
||||
print("X server processes:")
|
||||
x_lines = [
|
||||
line
|
||||
for line in run(["ps", "-eo", "user,args"]).splitlines()
|
||||
if "Xorg" in line or "Xwayland" in line
|
||||
]
|
||||
if x_lines:
|
||||
for line in x_lines:
|
||||
print(f" {line}")
|
||||
else:
|
||||
print(" <none found>")
|
||||
|
||||
print()
|
||||
print("recommended SSH launch:")
|
||||
print(" cd <workspace>/screen")
|
||||
print(" bash run_fullscreen_quit.sh")
|
||||
print()
|
||||
print("if authorization fails, run this on the Nano desktop terminal once:")
|
||||
print(f" DISPLAY=:0 xhost +SI:localuser:{current_user()}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
AUTOSTART_DIR="$HOME/.config/autostart"
|
||||
DESKTOP_FILE="$AUTOSTART_DIR/sim2real-screen.desktop"
|
||||
|
||||
mkdir -p "$AUTOSTART_DIR"
|
||||
chmod +x "$SCRIPT_DIR/run_fullscreen_quit.sh"
|
||||
|
||||
cat > "$DESKTOP_FILE" <<EOF
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=sim2real Screen
|
||||
Comment=Start the sim2real touch control panel
|
||||
Exec=$SCRIPT_DIR/run_fullscreen_quit.sh
|
||||
Path=$SCRIPT_DIR
|
||||
Terminal=false
|
||||
X-GNOME-Autostart-enabled=true
|
||||
StartupNotify=false
|
||||
EOF
|
||||
|
||||
echo "Installed desktop autostart:"
|
||||
echo " $DESKTOP_FILE"
|
||||
echo
|
||||
echo "It will start after this user logs into the graphical desktop."
|
||||
echo "For boot-time use, enable automatic login for this user on the Orin desktop."
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if ! command -v systemctl >/dev/null 2>&1; then
|
||||
echo "systemctl not found; this installer is for systemd-based Linux." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SERVICE_NAME="sim2real-screen.service"
|
||||
SERVICE_PATH="/etc/systemd/system/$SERVICE_NAME"
|
||||
|
||||
if [ "${EUID:-$(id -u)}" -eq 0 ]; then
|
||||
RUN_USER="${1:-${SUDO_USER:-rc2}}"
|
||||
else
|
||||
RUN_USER="${1:-$(id -un)}"
|
||||
fi
|
||||
|
||||
if ! id "$RUN_USER" >/dev/null 2>&1; then
|
||||
echo "User '$RUN_USER' does not exist. Usage: bash install_boot_service.sh rc2" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RUN_GROUP="$(id -gn "$RUN_USER")"
|
||||
RUN_HOME="$(getent passwd "$RUN_USER" | cut -d: -f6)"
|
||||
AUTOSTART_FILE="$RUN_HOME/.config/autostart/sim2real-screen.desktop"
|
||||
|
||||
chmod +x "$SCRIPT_DIR/run_fullscreen_quit.sh" "$SCRIPT_DIR/run_boot_screen_service.sh"
|
||||
if [ -f "$AUTOSTART_FILE" ]; then
|
||||
rm -f "$AUTOSTART_FILE"
|
||||
echo "Removed desktop autostart to avoid duplicate screen instances:"
|
||||
echo " $AUTOSTART_FILE"
|
||||
fi
|
||||
|
||||
SERVICE_CONTENT="[Unit]
|
||||
Description=sim2real touchscreen control panel
|
||||
Wants=display-manager.service
|
||||
After=systemd-user-sessions.service display-manager.service
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$RUN_USER
|
||||
Group=$RUN_GROUP
|
||||
WorkingDirectory=$SCRIPT_DIR
|
||||
Environment=HOME=$RUN_HOME
|
||||
Environment=DISPLAY=:0
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
ExecStart=$SCRIPT_DIR/run_boot_screen_service.sh
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
KillSignal=SIGINT
|
||||
TimeoutStopSec=20
|
||||
|
||||
[Install]
|
||||
WantedBy=graphical.target
|
||||
"
|
||||
|
||||
printf "%s" "$SERVICE_CONTENT" | sudo tee "$SERVICE_PATH" >/dev/null
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable "$SERVICE_NAME"
|
||||
|
||||
echo "Installed and enabled:"
|
||||
echo " $SERVICE_PATH"
|
||||
echo
|
||||
echo "Start now:"
|
||||
echo " sudo systemctl restart $SERVICE_NAME"
|
||||
echo
|
||||
echo "Check status/logs:"
|
||||
echo " systemctl status $SERVICE_NAME --no-pager"
|
||||
echo " journalctl -u $SERVICE_NAME -f"
|
||||
echo
|
||||
echo "Important: the graphical desktop for user '$RUN_USER' must auto-login, otherwise Tk cannot open DISPLAY=:0."
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
export DISPLAY="${DISPLAY:-:0}"
|
||||
export PYTHONUNBUFFERED=1
|
||||
|
||||
echo "[sim2real-screen] service starting as $(id -un), DISPLAY=$DISPLAY"
|
||||
|
||||
for _ in $(seq 1 120); do
|
||||
if [ -S "/tmp/.X11-unix/X${DISPLAY#:}" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [ ! -S "/tmp/.X11-unix/X${DISPLAY#:}" ]; then
|
||||
echo "[sim2real-screen] X11 socket for DISPLAY=$DISPLAY not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$SCRIPT_DIR/run_fullscreen_quit.sh"
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
set -u
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
export DISPLAY="${DISPLAY:-:0}"
|
||||
|
||||
if [ -z "${XAUTHORITY:-}" ]; then
|
||||
UID_VALUE="$(id -u)"
|
||||
|
||||
for candidate in \
|
||||
"$HOME/.Xauthority" \
|
||||
"/run/user/$UID_VALUE/gdm/Xauthority" \
|
||||
"/run/user/$UID_VALUE/Xauthority"
|
||||
do
|
||||
if [ -f "$candidate" ]; then
|
||||
export XAUTHORITY="$candidate"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
python3 fullscreen_quit.py
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SERVICE_NAME="sim2real-screen.service"
|
||||
SERVICE_PATH="/etc/systemd/system/$SERVICE_NAME"
|
||||
|
||||
sudo systemctl disable --now "$SERVICE_NAME" 2>/dev/null || true
|
||||
sudo rm -f "$SERVICE_PATH"
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
echo "Removed $SERVICE_NAME"
|
||||
Reference in New Issue
Block a user