#!/bin/bash # jog_probe.sh — Mac から, Pi の mechArm で根元 j0 を 4 つの動かし方で動かし, なめらかさと限界を測る (2026-11-03) # # tools/jog_probe.sh A 1 回の send_angles / B 送り直し (今の長押し) / C 送り直し + fresh_mode / D jog (speed 10・30) # テストごとに Enter で進む。q と Enter で止める # # 流れ (tools/servo_check.sh と同じ): # 0. KIOXIA のマウントを確かめ, diag/jog_probe_{日時}/ を作る # 1. tools/pi/jog_probe_pi.py を Pi へ送る # 2. デーモンを止める (シリアルを直接使うため). 止まったこと・5555 とシリアルが空いたことを確かめる # 3. Pi で jog_probe_pi.py を流す (PYTHONPATH に 2.9.6 の置き場所を入れる) # 4. 終わったら (途中で止めても) 測るプロセスが残っていれば止め, 結果の JSON を持ち帰り, デーモンを元の起動のしかたで戻す # 画面の出力は全部 console.txt に残す。 set -u PI=ubuntu@192.168.2.1 KEY="$HOME/.ssh/id_rsa_pi" SSH_OPTS=(-i "$KEY" -o ConnectTimeout=5 -o ServerAliveInterval=5 -o ServerAliveCountMax=3) # 切れたら約 15 秒で返る SSH=(ssh "${SSH_OPTS[@]}" "$PI") # 標準入力を使うもの (heredoc) SSHN=(ssh -n "${SSH_OPTS[@]}" "$PI") # 端末の入力を読まないもの UNIT=mecharm-daemon.service DATA_ROOT="${SERVO_CHECK_DATA_ROOT:-/Volumes/KIOXIA/r2r2r-data}" PI_SCRIPT=/home/ubuntu/jog_probe_pi.py PI_PYTHONPATH=/usr/local/lib/python2.7/dist-packages # 対話シェルの ~/.bashrc と同じ (pymycobot 2.9.6) DAEMON_UP_WAIT=${SERVO_CHECK_UP_WAIT:-60} # 戻したデーモンが 5555 を開くまで待つ上限 (秒) HERE="$(cd "$(dirname "$0")" && pwd)" case "${1:-}" in "") ;; *) echo "使い方: $0" >&2; exit 2 ;; esac if [ ! -d "$DATA_ROOT/diag" ]; then echo "ABORT: $DATA_ROOT/diag がない (KIOXIA がマウントされていない?)" >&2 exit 1 fi STAMP=$(date +%Y%m%d_%H%M%S) OUT="$DATA_ROOT/diag/jog_probe_$STAMP" if [ -e "$OUT" ]; then echo "ABORT: $OUT がすでにある" >&2 exit 1 fi mkdir "$OUT" || exit 1 PI_OUT=/tmp/jog_probe_$STAMP.json # Pi のデーモンの状態を key=value で出す remote_state() { "${SSH[@]}" 'bash -s' <<'REMOTE' pid=$(pgrep -f '[m]echarm_daemon\.py' | head -n 1) if [ "$(systemctl is-active mecharm-daemon.service 2>/dev/null)" = active ]; then mode=systemd elif [ -n "$pid" ]; then mode=manual else mode=none; fi echo "mode=$mode" echo "pid=${pid:-なし}" if ss -ltn | grep -q ':5555 '; then echo "listen=yes"; else echo "listen=no"; fi if [ -n "$pid" ]; then pp=$(tr '\0' '\n' < /proc/$pid/environ 2>/dev/null | sed -n 's/^PYTHONPATH=//p') echo "daemon_pythonpath=${pp:-(なし)}" fi # /dev/ttyAMA0 を開いているプロセス (root のものも見るため sudo。読めなければ「不明」) if sudo -n true 2>/dev/null; then u=$(sudo -n find /proc/[0-9]*/fd -lname /dev/ttyAMA0 2>/dev/null | cut -d/ -f3 | sort -u | tr '\n' ' ') u=${u% } echo "serial_users=${u:-(なし)}" else echo "serial_users=不明" fi if pgrep -f '[j]og_probe_pi\.py' > /dev/null; then echo "checker=yes"; else echo "checker=no"; fi REMOTE } state_val() { sed -n "s/^$1=//p" <<<"$2" | head -n 1; } MODE="" RESTORED=0 restore() { # デーモンを元に戻す (MODE が決まる前に終わったときは何もしない) [ "$RESTORED" = 1 ] && return RESTORED=1 [ -n "$MODE" ] || return # 点検のプロセスが残っていれば止めてから戻す (シリアルを二重に開かない) "${SSHN[@]}" "pkill -INT -f '[j]og_probe_pi\.py'; for i in 1 2 3 4 5; do pgrep -f '[j]og_probe_pi\.py' > /dev/null || exit 0; sleep 1; done; pkill -KILL -f '[j]og_probe_pi\.py'; sleep 1" scp -i "$KEY" -q -o ConnectTimeout=5 "$PI:$PI_OUT" "$OUT/result.json" 2>/dev/null && echo "結果の JSON: $OUT/result.json" || echo "結果の JSON は持ち帰れなかった" case "$MODE" in systemd) echo "--- デーモンを戻す (systemctl start)" "${SSHN[@]}" "sudo systemctl start $UNIT" ;; manual) echo "--- デーモンを戻す (対話シェルで手で起動)" "${SSHN[@]}" 'bash -ic "nohup python3 /home/ubuntu/mecharm_daemon.py >> /home/ubuntu/daemon.log 2>&1 &"' ;; *) return ;; esac local i st for ((i = 0; i < DAEMON_UP_WAIT; i += 5)); do st=$(remote_state) [ "$(state_val listen "$st")" = yes ] && break sleep 5 done echo "$st" if [ "$(state_val listen "$st")" = yes ]; then echo "デーモンは戻った (5555 LISTEN)" case "$(state_val daemon_pythonpath "$st")" in *python2.7*) ;; *) echo "注意: デーモンの PYTHONPATH に python2.7 がない (pymycobot 4.0.4 を読んでいるかもしれない)" ;; esac else echo "注意: デーモンが 5555 を開いていない。tools/daemon_ctl.sh status で確かめる" fi } main() { echo "jog_probe $STAMP (結果: $OUT)" trap 'restore' EXIT trap 'exit 130' INT TERM scp -i "$KEY" -q -o ConnectTimeout=5 "$HERE/pi/jog_probe_pi.py" "$PI:$PI_SCRIPT" || { echo "ABORT: Pi へ送れなかった"; exit 1; } echo "--- デーモンの状態 (止める前)" local st st=$(remote_state) || { echo "ABORT: Pi につながらない"; exit 1; } echo "$st" MODE=$(state_val mode "$st") case "$MODE" in systemd) "${SSHN[@]}" "sudo systemctl stop $UNIT" ;; manual) "${SSHN[@]}" "pkill -TERM -f '[m]echarm_daemon\.py'" ;; none) echo "デーモンは動いていない (終わったあとも起動しない)" ;; *) echo "ABORT: デーモンの状態が読めない"; MODE=""; exit 1 ;; esac local i for ((i = 0; i < 10; i++)); do st=$(remote_state) [ "$(state_val pid "$st")" = なし ] && [ "$(state_val listen "$st")" = no ] && break sleep 1 done echo "--- デーモンの状態 (止めたあと)" echo "$st" if [ "$(state_val pid "$st")" != なし ]; then echo "ABORT: デーモンが止まらない" exit 1 fi if [ "$(state_val listen "$st")" != no ]; then echo "ABORT: 5555 がまだ開いている" exit 1 fi if [ "$(state_val serial_users "$st")" != "(なし)" ]; then echo "ABORT: /dev/ttyAMA0 を開いているプロセスがある・確かめられない ($(state_val serial_users "$st"))" exit 1 fi ssh -tt "${SSH_OPTS[@]}" "$PI" "PYTHONPATH=$PI_PYTHONPATH python3 -u $PI_SCRIPT --out $PI_OUT" local rc=$? echo "--- jog_probe_pi.py の終了コード: $rc" exit "$rc" } main 2>&1 | tee -i "$OUT/console.txt" exit "${PIPESTATUS[0]}"