engineai_fleet/tools/probe_eng.sh
2026-08-27 16:24:12 +04:00

119 lines
5.3 KiB
Bash

#!/usr/bin/env bash
# probe_eng.sh — read-only EngineAI PM01 discovery.
#
# bash tools/probe_eng.sh <ip> [user]
# bash tools/probe_eng.sh 10.210.136.150 ubuntu
#
# Prints what the robot ACTUALLY exposes, each line labelled with the .env
# variable it feeds. Installs nothing, writes nothing, publishes to no topic —
# safe to run against a live robot.
#
# Auth: uses an ssh key if FLEET_SSH_KEY is set, otherwise sshpass with
# FLEET_SSH_PASS (default "ubuntu"). Set FLEET_SSH_PASS in the environment
# rather than editing this file.
set -uo pipefail
IP="${1:-}"
USER_="${2:-ubuntu}"
if [ -z "$IP" ]; then
echo "usage: bash tools/probe_eng.sh <ip> [user]" >&2
exit 2
fi
SSH_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=8 -o BatchMode=no"
if [ -n "${FLEET_SSH_KEY:-}" ]; then
RUN() { ssh $SSH_OPTS -i "$FLEET_SSH_KEY" "$USER_@$IP" "$@"; }
elif command -v sshpass >/dev/null 2>&1; then
RUN() { sshpass -p "${FLEET_SSH_PASS:-ubuntu}" ssh $SSH_OPTS "$USER_@$IP" "$@"; }
else
RUN() { ssh $SSH_OPTS "$USER_@$IP" "$@"; }
fi
hdr() { printf '\n\033[1m== %s\033[0m\n' "$1"; }
# The robot's own environment file is the source of truth for ROS_DOMAIN_ID,
# RMW_IMPLEMENTATION and CYCLONEDDS_URI. Sourcing it (rather than guessing 0)
# is the difference between seeing 44 topics and seeing 2.
ROSENV='set +u
. /opt/ros/humble/setup.bash >/dev/null 2>&1
. /app/applications/install/bringup/ros_env.sh >/dev/null 2>&1'
hdr "host (-> SOFTWARE_*, MAC_INTERFACE, STORAGE_PATH)"
RUN "hostname; uname -srm; grep PRETTY_NAME /etc/os-release
echo -n 'board : '; tr -d '\0' < /proc/device-tree/model 2>/dev/null; echo
echo -n 'board_serial: '; tr -d '\0' < /proc/device-tree/serial-number 2>/dev/null; echo
echo -n 'l4t : '; head -1 /etc/nv_tegra_release 2>/dev/null
echo -n 'product : '; cat /app/applications/install/bringup/product.env 2>/dev/null
echo '--- NICs (MAC_INTERFACE = the one carrying the LAN address) ---'
ip -o -4 addr show | awk '{printf \" %-10s %-18s mac=\", \$2, \$4}
{\"cat /sys/class/net/\" \$2 \"/address\" | getline m; print m}'
echo '--- disk (STORAGE_PATH) ---'; df -h / | tail -1"
hdr "ROS env (-> ROS_DOMAIN_ID; the unit must source ros_env.sh)"
RUN "cat /app/applications/install/bringup/ros_env.sh 2>/dev/null
echo '--- CycloneDDS interface pinning ---'
cat /app/applications/install/bringup/cyclonedds.xml 2>/dev/null"
hdr "ROS topics (-> ENG_TOPIC_* / ENG_TYPE_*)"
RUN "$ROSENV; timeout 30 ros2 topic list -t 2>/dev/null"
hdr "message definitions (-> ENG_FIELD_*)"
RUN "for m in PowerInfo JointState MotorDebug MotionState; do
echo \"--- \$m ---\"
find /app/applications/install/interface_protocol -name \"\$m.msg\" \
-exec cat {} \; 2>/dev/null
echo
done"
hdr "live samples (-> verify ENG_SOC_SCALE / ENG_CURRENT_SIGN / units)"
RUN "$ROSENV
echo '--- /hardware/power_info (battery: percentage, voltage, current) ---'
timeout 12 ros2 topic echo --once /hardware/power_info 2>/dev/null
echo '--- /motion/motion_state (control.mode + switchable_modes) ---'
timeout 12 ros2 topic echo --once /motion/motion_state 2>/dev/null
echo '--- /hardware/motor_debug (motor_temp; first lines only) ---'
timeout 12 ros2 topic echo --once /hardware/motor_debug 2>/dev/null | head -12"
hdr "publish rates (-> ENG_JOINT_MIN_PERIOD / ENG_MOTOR_MIN_PERIOD)"
RUN "$ROSENV
for t in /hardware/power_info /hardware/joint_state /hardware/motor_debug /motion/motion_state; do
printf ' %-28s ' \"\$t\"
timeout 8 ros2 topic hz \$t 2>/dev/null | grep -m1 average || echo 'NO DATA'
done"
hdr "CHARGE DIRECTION (-> ENG_CURRENT_SIGN) ~45s"
echo " If percentage FALLS while current is POSITIVE, positive = discharge"
echo " and ENG_CURRENT_SIGN must be -1 (otherwise the robot reports 'charging'"
echo " forever while its battery drains)."
RUN "$ROSENV
for i in 1 2 3; do
printf ' %s ' \"\$(date +%H:%M:%S)\"
timeout 8 ros2 topic echo --once /hardware/power_info 2>/dev/null \
| tr '\n' ' ' | sed 's/---//'
echo
[ \$i -lt 3 ] && sleep 18
done"
hdr "position sources (-> ENG_POSITION_SOURCE / ENG_TOPIC_ODOM)"
RUN "$ROSENV
echo -n ' odometry topics: '
timeout 20 ros2 topic list 2>/dev/null | grep -iE 'odom|/tf$|amcl|pose' || echo 'NONE (position reports null)'
echo -n ' sanad nav status: '
curl -s -m5 http://127.0.0.1:8014/api/nav/status 2>/dev/null | head -c 220; echo"
hdr "dashboards / remote (-> REMOTE_PORTS, SSH_USER)"
RUN "echo '--- listening ports ---'; ss -tlnp 2>/dev/null | awk 'NR>1{print \" \" \$4}' | sort -u
for p in 8014 8001 9002 9003 9004 8765; do
printf ' %-6s ' \$p
curl -s -m3 -o /dev/null -w 'HTTP %{http_code}' http://127.0.0.1:\$p/ 2>/dev/null || printf 'closed'
curl -s -m3 http://127.0.0.1:\$p/ 2>/dev/null | grep -qi 'sanad\|dashboard' && printf ' <- dashboard page'
echo
done"
hdr "project logs (-> PROJECT_LOG_CONTAINER; needs root)"
RUN "sudo -n docker ps --format ' {{.Names}} {{.Status}}' 2>/dev/null \
|| echo ' (needs sudo; the agent runs as root and can read these)'"
hdr "done"
echo "Set the values above in agent/.env, then: systemctl restart sanad-api-eng"