62 lines
3.3 KiB
Bash
Executable File
62 lines
3.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Container entrypoint for SanadR1. Waits for the robot link (eth10) to be UP with
|
|
# its 192.168.123.x address before launching, so the single per-process DDS init
|
|
# (arm.init → ChannelFactoryInitialize) binds the right interface. Mirrors the
|
|
# conda start_sanad.sh eth10 wait; without it, on a cold robot boot the process
|
|
# would init DDS on a not-yet-ready iface and silently run hardware-dead.
|
|
set -u
|
|
|
|
IFACE="${SANAD_DDS_INTERFACE:-eth10}"
|
|
PORT="${PORT:-8001}"
|
|
|
|
echo "[entrypoint] waiting up to 25s for ${IFACE} to be UP with a 192.168.123.x IP…"
|
|
for i in $(seq 1 25); do
|
|
if ip link show "$IFACE" 2>/dev/null | grep -q "state UP" \
|
|
&& ip -4 -o addr show "$IFACE" 2>/dev/null | grep -q "192.168.123."; then
|
|
echo "[entrypoint] ${IFACE} ready: $(ip -4 -o addr show "$IFACE" | awk '{print $4}')"
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
if ! ip link show "$IFACE" 2>/dev/null | grep -q "state UP"; then
|
|
echo "[entrypoint] WARNING: ${IFACE} not UP after 25s — launching anyway; robot DDS (arm/loco/audio) may be unavailable this session" >&2
|
|
fi
|
|
|
|
# ── audio path ───────────────────────────────────────────────────────────────
|
|
# If a USB audio device was passed in (--device /dev/snd), run as the non-root
|
|
# 'sanad' user with a per-user PulseAudio so the JBL/Anker-style device profiles
|
|
# work (Sanad refuses to touch audio as root). Otherwise keep the original root
|
|
# path — the R1's DDS chest speaker + UDP mic need no local sound stack.
|
|
if [ -e /dev/snd ]; then
|
|
export XDG_RUNTIME_DIR=/run/user/1000
|
|
# Volumes mount root-owned; hand them + the runtime dir to the app user.
|
|
chown -R sanad:sanad /opt/SanadR1/data /opt/SanadR1/logs "$XDG_RUNTIME_DIR" 2>/dev/null || true
|
|
[ -s /etc/machine-id ] || tr -d - < /proc/sys/kernel/random/uuid > /etc/machine-id 2>/dev/null || true
|
|
echo "[entrypoint] /dev/snd present — starting PulseAudio (USB audio mode)"
|
|
setpriv --reuid sanad --regid sanad --init-groups \
|
|
env XDG_RUNTIME_DIR="$XDG_RUNTIME_DIR" HOME=/home/sanad \
|
|
pulseaudio --start --exit-idle-time=-1 >/dev/null 2>&1 \
|
|
|| echo "[entrypoint] WARNING: PulseAudio failed to start" >&2
|
|
# udev doesn't run in the container, so PulseAudio's udev-detect finds no
|
|
# cards. Load each USB ALSA card BY NAME (skip the Jetson built-in HDA/APE) so
|
|
# its sink/source are named for the device — that's what the Anker/JBL-style
|
|
# device profiles match on (e.g. alsa_output.PowerConf.analog-stereo).
|
|
sleep 1
|
|
for _card in $(aplay -l 2>/dev/null | sed -n 's/^card [0-9][0-9]*: \([A-Za-z0-9_]*\) .*/\1/p' | sort -u); do
|
|
case "$_card" in
|
|
HDA|APE|"") : ;;
|
|
*) echo "[entrypoint] loading USB audio card: ${_card}"
|
|
setpriv --reuid sanad --regid sanad --init-groups \
|
|
env XDG_RUNTIME_DIR="$XDG_RUNTIME_DIR" \
|
|
pactl load-module module-alsa-card device_id="${_card}" >/dev/null 2>&1 || true ;;
|
|
esac
|
|
done
|
|
echo "[entrypoint] launching main.py --port ${PORT} as user 'sanad'"
|
|
exec setpriv --reuid sanad --regid sanad --init-groups \
|
|
env XDG_RUNTIME_DIR="$XDG_RUNTIME_DIR" HOME=/home/sanad \
|
|
python3 main.py --port "${PORT}"
|
|
else
|
|
echo "[entrypoint] no /dev/snd — DDS audio only; launching main.py --port ${PORT} as root"
|
|
exec python3 main.py --port "${PORT}"
|
|
fi
|