252 lines
8.8 KiB
Bash
Executable File
252 lines
8.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# ./launch_robot.sh [node_names...] # launch specific nodes
|
|
# ./launch_robot.sh all # launch all nodes in launch.conf
|
|
|
|
# Safer bash defaults for this script
|
|
set -Eeuo pipefail
|
|
|
|
# Argument check
|
|
TARGET_NODES=()
|
|
LAUNCH_ALL=false
|
|
|
|
if [ $# -eq 0 ]; then
|
|
echo "Error: No target nodes specified."
|
|
echo "Usage: $0 [node1 node2 ...] | all"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$1" == "all" ]]; then
|
|
LAUNCH_ALL=true
|
|
else
|
|
TARGET_NODES=("$@")
|
|
fi
|
|
|
|
# Workspace directory defaults to the current working directory when the script is run
|
|
WS_DIR="${WS_DIR:-$PWD}"
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
|
|
CONFIG_FILE="${CONFIG_FILE:-${SCRIPT_DIR}/launch.conf}"
|
|
|
|
# 获取日期和时间戳函数
|
|
date_day() { date +"%Y%m%d"; }
|
|
readable_timestamp() { date +"%Y%m%d_%H%M%S"; }
|
|
|
|
# 1. 自动创建当天的日志根目录并包含本次启动的时间子目录
|
|
DAILY_LOG_ROOT="${WS_DIR}/logs/$(date_day)"
|
|
LOG_DIR="${DAILY_LOG_ROOT}/robot_logs_$(readable_timestamp)"
|
|
# LOG_ORIGIN_DIR="${LOG_DIR}/origin"
|
|
mkdir -p "${LOG_DIR}"
|
|
# mkdir -p "${LOG_ORIGIN_DIR}"
|
|
|
|
# 2. 导出相关环境变量
|
|
#export ROS_LOG_DIR="${LOG_ORIGIN_DIR}"
|
|
# ROS 2 无法原生完全禁用文件日志,将其指向 /tmp 下的临时目录以避免持久化保存
|
|
export ROS_LOG_DIR="/tmp/ros_log_discard_$(readable_timestamp)"
|
|
export PYTHONUNBUFFERED=1
|
|
export RCUTILS_LOGGING_BUFFERED_STREAM=1
|
|
export RCUTILS_COLORIZED_OUTPUT=0
|
|
|
|
# title|mode|package|target|args
|
|
# mode: run => ros2 run <pkg> <executable>
|
|
# launch => ros2 launch <pkg> <launch_file.py>
|
|
if [[ -f "${CONFIG_FILE}" ]]; then
|
|
mapfile -t COMPONENTS < <(grep -vE '^\s*#' "${CONFIG_FILE}" | sed '/^\s*$/d')
|
|
else
|
|
echo "no configuration file found at ${CONFIG_FILE}, exiting." >&2
|
|
exit 1
|
|
fi
|
|
|
|
compose_terminal_script() {
|
|
local title="$1" cmds_block="$2"
|
|
cat <<EOF
|
|
echo Launching Robot ${title}
|
|
cd "${WS_DIR}"
|
|
set +u; source install/setup.bash || { echo "Workspace not built (missing install/setup.bash). Run: colcon build" >&2; }; set -u;
|
|
# Freeze terminal title so it won't be changed by shell rc/profile
|
|
printf '\033]0;%s\007' "${title}"
|
|
${cmds_block}
|
|
echo "All processes launched for: Launching Robot ${title}"
|
|
exec bash --noprofile --norc
|
|
EOF
|
|
}
|
|
|
|
launch_with_gnome_terminal() {
|
|
# Build unique title list
|
|
local unique_titles=()
|
|
for entry in "${COMPONENTS[@]}"; do
|
|
IFS='|' read -r title mode pkg target args <<<"$entry"
|
|
|
|
# --- Filter Logic ---
|
|
if [ "$LAUNCH_ALL" = false ]; then
|
|
local match_found=false
|
|
for node_filter in "${TARGET_NODES[@]}"; do
|
|
# Match against package name or executable name
|
|
if [[ "$node_filter" == "$pkg" ]] || [[ "$node_filter" == "$target" ]]; then
|
|
match_found=true
|
|
break
|
|
fi
|
|
done
|
|
if [ "$match_found" = false ]; then
|
|
continue
|
|
fi
|
|
fi
|
|
# --------------------
|
|
|
|
local found=0
|
|
for t in "${unique_titles[@]:-}"; do
|
|
if [[ "$t" == "$title" ]]; then found=1; break; fi
|
|
done
|
|
if [[ $found -eq 0 ]]; then unique_titles+=("$title"); fi
|
|
done
|
|
|
|
# For each title, gather commands and open a terminal
|
|
for title in "${unique_titles[@]}"; do
|
|
local cmds_block=""
|
|
for entry in "${COMPONENTS[@]}"; do
|
|
IFS='|' read -r etitle mode pkg target args <<<"$entry"
|
|
[[ "$etitle" != "$title" ]] && continue
|
|
|
|
# --- Filter Logic (Repeated for execution block) ---
|
|
if [ "$LAUNCH_ALL" = false ]; then
|
|
local match_found=false
|
|
for node_filter in "${TARGET_NODES[@]}"; do
|
|
# Match against package name or executable name
|
|
if [[ "$node_filter" == "$pkg" ]] || [[ "$node_filter" == "$target" ]]; then
|
|
match_found=true
|
|
break
|
|
fi
|
|
done
|
|
if [ "$match_found" = false ]; then
|
|
continue
|
|
fi
|
|
fi
|
|
# --------------------
|
|
|
|
args="${args:-}"
|
|
local ros_cmd
|
|
if [[ "${pkg}" == "ethercat_control" ]]; then
|
|
ros_cmd="taskset -c 7 ./cpu7.sh"
|
|
elif [[ "$mode" == "launch" ]]; then
|
|
ros_cmd="ros2 launch ${pkg} ${target} ${args}"
|
|
else
|
|
ros_cmd="ros2 run ${pkg} ${target} ${args}"
|
|
fi
|
|
|
|
if [[ "${pkg}" == "robot_control" ]]; then
|
|
ros_cmd="echo 'Waiting for EtherCAT slaves to be OP...'; while ! ethercat slaves 2>&1 | grep -q 'OP' || ethercat slaves 2>&1 | grep -v 'OP' | grep -q .; do sleep 2; done; ${ros_cmd}"
|
|
fi
|
|
|
|
# 3. 为每个组件生成带明文时间戳的日志文件名并添加重定向
|
|
local log_file="${LOG_DIR}/${etitle}_${target}_$(readable_timestamp).log"
|
|
ros_cmd="{ ${ros_cmd}; } 2>&1 | tee \"${log_file}\""
|
|
|
|
cmds_block+="${ros_cmd} &"$'\n'
|
|
done
|
|
|
|
# If no commands collected for this title (because all were filtered out), skip launching terminal
|
|
if [[ -z "$cmds_block" ]]; then continue; fi
|
|
|
|
# Compose the final script for this terminal
|
|
local cmd
|
|
cmd=$(compose_terminal_script "$title" "$cmds_block")
|
|
|
|
# gnome-terminal --title="${title}" -- bash -lc "$cmd" &
|
|
bash -c "$cmd" &
|
|
sleep 3
|
|
done
|
|
}
|
|
launch_with_xterm() {
|
|
local unique_titles=()
|
|
for entry in "${COMPONENTS[@]}"; do
|
|
IFS='|' read -r title mode pkg target args <<<"$entry"
|
|
|
|
# --- Filter Logic ---
|
|
if [ "$LAUNCH_ALL" = false ]; then
|
|
local match_found=false
|
|
for node_filter in "${TARGET_NODES[@]}"; do
|
|
# Match against package name or executable name
|
|
if [[ "$node_filter" == "$pkg" ]] || [[ "$node_filter" == "$target" ]]; then
|
|
match_found=true
|
|
break
|
|
fi
|
|
done
|
|
if [ "$match_found" = false ]; then
|
|
continue
|
|
fi
|
|
fi
|
|
# --------------------
|
|
|
|
local found=0
|
|
for t in "${unique_titles[@]:-}"; do
|
|
if [[ "$t" == "$title" ]]; then found=1; break; fi
|
|
done
|
|
if [[ $found -eq 0 ]]; then unique_titles+=("$title"); fi
|
|
done
|
|
|
|
for title in "${unique_titles[@]}"; do
|
|
local cmds_block=""
|
|
for entry in "${COMPONENTS[@]}"; do
|
|
IFS='|' read -r etitle mode pkg target args <<<"$entry"
|
|
[[ "$etitle" != "$title" ]] && continue
|
|
|
|
# --- Filter Logic (Repeated for execution block) ---
|
|
if [ "$LAUNCH_ALL" = false ]; then
|
|
local match_found=false
|
|
for node_filter in "${TARGET_NODES[@]}"; do
|
|
# Match against package name or executable name
|
|
if [[ "$node_filter" == "$pkg" ]] || [[ "$node_filter" == "$target" ]]; then
|
|
match_found=true
|
|
break
|
|
fi
|
|
done
|
|
if [ "$match_found" = false ]; then
|
|
continue
|
|
fi
|
|
fi
|
|
# --------------------
|
|
|
|
args="${args:-}"
|
|
local ros_cmd
|
|
if [[ "${pkg}" == "ethercat_control" ]]; then
|
|
ros_cmd="taskset -c 7 ./cpu7.sh"
|
|
elif [[ "$mode" == "launch" ]]; then
|
|
ros_cmd="ros2 launch ${pkg} ${target} ${args}"
|
|
else
|
|
ros_cmd="ros2 run ${pkg} ${target} ${args}"
|
|
fi
|
|
|
|
if [[ "${pkg}" == "robot_control" ]]; then
|
|
ros_cmd="echo 'Waiting for EtherCAT slaves to be OP...'; while ! ethercat slaves 2>&1 | grep -q 'OP' || ethercat slaves 2>&1 | grep -v 'OP' | grep -q .; do sleep 2; done; ${ros_cmd}"
|
|
fi
|
|
|
|
# 3. 为每个组件生成带明文时间戳的日志文件名并添加重定向
|
|
local log_file="${LOG_DIR}/${etitle}_${target}_$(readable_timestamp).log"
|
|
ros_cmd="{ ${ros_cmd}; } 2>&1 | tee \"${log_file}\""
|
|
|
|
cmds_block+="${ros_cmd} &"$'\n'
|
|
done
|
|
|
|
# If no commands collected for this title (because all were filtered out), skip launching terminal
|
|
if [[ -z "$cmds_block" ]]; then continue; fi
|
|
|
|
local cmd
|
|
cmd=$(compose_terminal_script "$title" "$cmds_block")
|
|
xterm -T "${title}" -hold -e bash -lc "$cmd" &
|
|
done
|
|
}
|
|
main() {
|
|
echo "Starting robot components..."
|
|
if command -v gnome-terminal >/dev/null 2>&1; then
|
|
echo "Using gnome-terminal"
|
|
launch_with_gnome_terminal
|
|
elif command -v xterm >/dev/null 2>&1; then
|
|
echo "Using xterm"
|
|
launch_with_xterm
|
|
else
|
|
echo "No terminal emulator found (gnome-terminal or xterm). Proceeding with background execution." >&2
|
|
launch_with_gnome_terminal
|
|
fi
|
|
}
|
|
|
|
main "$@"
|