|
1 | | -#!/bin/bash |
2 | | -set -e |
| 1 | +#!/usr/bin/env bash |
| 2 | +set -euo pipefail |
| 3 | + |
| 4 | +########################### |
| 5 | +# CONFIG & ENVIRONMENT |
| 6 | +########################### |
| 7 | +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
| 8 | +WORKSPACE=~/ros2_ws |
| 9 | +LOG_DIR="${SCRIPT_DIR}/logs" |
| 10 | +mkdir -p "$LOG_DIR" |
3 | 11 |
|
4 | | -# Load ROS 2 environment |
5 | 12 | echo "Setting up ROS 2 environment..." |
6 | | -. /opt/ros/humble/setup.sh |
7 | | -. ~/ros2_ws/install/setup.bash |
| 13 | +# Temporarily disable -u to avoid unbound variable errors |
| 14 | +set +u |
| 15 | +source "/opt/ros/humble/setup.sh" |
| 16 | +source "${WORKSPACE}/install/setup.bash" |
| 17 | +set -u |
| 18 | + |
8 | 19 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib |
9 | 20 |
|
10 | | -# Get the directory of this script dynamically |
11 | | -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
| 21 | +########################### |
| 22 | +# GLOBAL CLEANUP HANDLER |
| 23 | +########################### |
| 24 | +SIM_PID="" |
| 25 | +ORCA_PID="" |
| 26 | +CONTROLLER_PID="" |
| 27 | +FILTER_PID="" |
| 28 | +TAIL_PIDS=() |
| 29 | + |
| 30 | +cleanup() { |
| 31 | + echo "Cleanup: stopping all background processes..." |
| 32 | + # Kill each background process by PID, if it exists |
| 33 | + for p in "$SIM_PID" "$ORCA_PID" "$CONTROLLER_PID" "$FILTER_PID"; do |
| 34 | + if [[ -n "$p" ]] && kill -0 "$p" 2>/dev/null; then |
| 35 | + echo "Killing process $p" |
| 36 | + kill -TERM "$p" || true |
| 37 | + fi |
| 38 | + done |
| 39 | + |
| 40 | + # Kill all tail processes |
| 41 | + for tpid in "${TAIL_PIDS[@]}"; do |
| 42 | + if [[ -n "$tpid" ]] && kill -0 "$tpid" 2>/dev/null; then |
| 43 | + kill -9 "$tpid" || true |
| 44 | + fi |
| 45 | + done |
12 | 46 |
|
13 | | -# Launch Stonefish Simulator |
14 | | -setsid ros2 launch stonefish_sim simulation_nogpu.launch.py & |
15 | | -SIM_PID=$! |
| 47 | + # Make sure everything is truly dead |
| 48 | + wait || true |
| 49 | +} |
| 50 | +trap cleanup EXIT |
| 51 | + |
| 52 | +########################### |
| 53 | +# HELPER: LAUNCH & MONITOR |
| 54 | +########################### |
| 55 | +launch_and_monitor() { |
| 56 | + local logfile="$1"; shift |
| 57 | + local launch_cmd=("$@") |
| 58 | + |
| 59 | + "${launch_cmd[@]}" &> "$logfile" & |
| 60 | + local child_pid=$! |
| 61 | + |
| 62 | + tail -F "$logfile" | while read -r line; do |
| 63 | + if [[ "$line" == *"[ERROR]"* ]]; then |
| 64 | + echo "[FATAL] Detected error in ${logfile}:" |
| 65 | + echo "$line" |
| 66 | + kill -TERM "$child_pid" 2>/dev/null || true |
| 67 | + exit 1 |
| 68 | + fi |
| 69 | + done & |
| 70 | + local tail_pid=$! |
| 71 | + |
| 72 | + TAIL_PIDS+=("$tail_pid") |
| 73 | + echo "$child_pid" |
| 74 | +} |
| 75 | + |
| 76 | +########################### |
| 77 | +# 1. LAUNCH SIMULATOR |
| 78 | +########################### |
| 79 | +echo "Launching Stonefish Simulator..." |
| 80 | +SIM_LOG="${LOG_DIR}/simulator.log" |
| 81 | +SIM_PID="$(launch_and_monitor "$SIM_LOG" ros2 launch stonefish_sim simulation_nogpu.launch.py)" |
16 | 82 | echo "Launched simulator with PID: $SIM_PID" |
17 | 83 |
|
18 | 84 | echo "Waiting for simulator to start..." |
19 | | -timeout 30s bash -c ' |
20 | | - while ! ros2 topic list | grep -q "/orca/odom"; do |
21 | | - sleep 1 |
22 | | - done || true' |
| 85 | +timeout 30s bash -c 'while ! ros2 topic list | grep -q "/orca/odom"; do sleep 1; done' |
23 | 86 | echo "Simulator started" |
24 | 87 |
|
25 | | -# Wait for odometry data |
26 | 88 | echo "Waiting for odom data..." |
27 | 89 | timeout 10s ros2 topic echo /orca/odom --once |
28 | 90 | echo "Got odom data" |
29 | 91 |
|
30 | | -# Launch ORCA Simulation |
31 | | -setsid ros2 launch stonefish_sim orca_sim.launch.py & |
32 | | -ORCA_PID=$! |
| 92 | +########################### |
| 93 | +# 2. LAUNCH ORCA |
| 94 | +########################### |
| 95 | +echo "Launching ORCA simulator..." |
| 96 | +ORCA_LOG="${LOG_DIR}/orca.log" |
| 97 | +ORCA_PID="$(launch_and_monitor "$ORCA_LOG" ros2 launch stonefish_sim orca_sim.launch.py)" |
33 | 98 | echo "Launched orca with PID: $ORCA_PID" |
34 | 99 |
|
35 | 100 | echo "Waiting for sim interface to start..." |
36 | | -timeout 30s bash -c 'until ros2 topic list | grep -q "/orca/pose"; do sleep 1; done' |
| 101 | +timeout 30s bash -c 'while ! ros2 topic list | grep -q "/orca/pose"; do sleep 1; done' |
37 | 102 | echo "Simulator started" |
38 | 103 |
|
39 | | -# Wait for pose data |
40 | 104 | echo "Waiting for pose data..." |
41 | 105 | timeout 10s ros2 topic echo /orca/pose --once |
42 | 106 | echo "Got pose data" |
43 | 107 |
|
44 | | -# Launch Controllers |
45 | | -setsid ros2 launch dp_adapt_backs_controller dp_adapt_backs_controller.launch.py & |
46 | | -CONTROLLER_PID=$! |
| 108 | +########################### |
| 109 | +# 3. LAUNCH CONTROLLERS |
| 110 | +########################### |
| 111 | +echo "Launching DP Adaptive Backstepping Controller..." |
| 112 | +CONTROLLER_LOG="${LOG_DIR}/dp_adapt.log" |
| 113 | +CONTROLLER_PID="$(launch_and_monitor "$CONTROLLER_LOG" ros2 launch dp_adapt_backs_controller dp_adapt_backs_controller.launch.py)" |
47 | 114 | echo "Launched controller with PID: $CONTROLLER_PID" |
48 | 115 |
|
49 | | -setsid ros2 launch reference_filter_dp reference_filter.launch.py & |
50 | | -FILTER_PID=$! |
| 116 | +echo "Launching reference_filter..." |
| 117 | +FILTER_LOG="${LOG_DIR}/filter.log" |
| 118 | +FILTER_PID="$(launch_and_monitor "$FILTER_LOG" ros2 launch reference_filter_dp reference_filter.launch.py)" |
51 | 119 | echo "Launched filter with PID: $FILTER_PID" |
52 | 120 |
|
53 | | -# Set operation mode |
| 121 | +########################### |
| 122 | +# 4. PUBLISH MSGS TO START |
| 123 | +########################### |
54 | 124 | echo "Turning off killswitch and setting operation mode to autonomous mode" |
55 | 125 | ros2 topic pub /orca/killswitch std_msgs/msg/Bool "{data: false}" -1 |
56 | 126 | ros2 topic pub /orca/operation_mode std_msgs/msg/String "{data: 'autonomous mode'}" -1 |
57 | 127 |
|
58 | | -# Send waypoint goal |
59 | | -echo "Sending goal" |
| 128 | +echo "Sending goal..." |
60 | 129 | python3 "$SCRIPT_DIR/send_goal.py" |
61 | 130 |
|
62 | | -# Check if goal reached |
63 | | -echo "Checking if goal reached" |
| 131 | +########################### |
| 132 | +# 5. CHECK GOAL |
| 133 | +########################### |
| 134 | +echo "Checking if goal reached..." |
64 | 135 | python3 "$SCRIPT_DIR/check_goal.py" |
65 | | - |
66 | 136 | if [ $? -ne 0 ]; then |
67 | | - echo "Test failed: Drone did not reach goal." |
68 | | - exit 1 |
| 137 | + echo "Test failed: Drone did not reach goal." |
| 138 | + exit 1 |
69 | 139 | else |
70 | | - echo "Test passed: Drone reached goal." |
| 140 | + echo "Test passed: Drone reached goal." |
71 | 141 | fi |
72 | 142 |
|
73 | | -# Terminate processes |
74 | | -kill -TERM -"$SIM_PID" -"$ORCA_PID" -"$CONTROLLER_PID" -"$FILTER_PID" |
| 143 | +########################### |
| 144 | +# 6. CLEAN SHUTDOWN |
| 145 | +########################### |
| 146 | +echo "Terminating all processes..." |
| 147 | +cleanup |
| 148 | +echo "All done!" |
0 commit comments