From 215b044ff01149208a94ae77e22af272567928e2 Mon Sep 17 00:00:00 2001 From: shb-png Date: Mon, 11 May 2026 22:05:13 +0000 Subject: [PATCH 01/35] separate launch scripts --- ...gup_pi.launch.py => bringup_all.launch.py} | 0 .../launch/bringup_jetson.launch.py | 80 +++++++++++++++++++ .../launch/bringup_rubik.launch.py | 32 ++++++++ 3 files changed, 112 insertions(+) rename src/autonomous_kart/autonomous_kart/launch/{bringup_pi.launch.py => bringup_all.launch.py} (100%) create mode 100644 src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py create mode 100644 src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_pi.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_all.launch.py similarity index 100% rename from src/autonomous_kart/autonomous_kart/launch/bringup_pi.launch.py rename to src/autonomous_kart/autonomous_kart/launch/bringup_all.launch.py diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py new file mode 100644 index 00000000..b63d91cd --- /dev/null +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py @@ -0,0 +1,80 @@ +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument, GroupAction +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node, SetParameter, SetParametersFromFile +from ament_index_python.packages import get_package_share_directory +import os + + +def generate_launch_description(): + pkg_share = get_package_share_directory("autonomous_kart") + + camera_yaml = os.path.join(pkg_share, "params", "camera.yaml") + gps_yaml = os.path.join(pkg_share, "params", "gps.yaml") + safety_yaml = os.path.join(pkg_share, "params", "safety.yaml") + system_yaml = os.path.join(pkg_share, "params", "system.yaml") + pathfinder_yaml = os.path.join(pkg_share, "params", "pathfinder.yaml") + localization_yaml = os.path.join(pkg_share, "params", "localization.yaml") + imu_yaml = os.path.join(pkg_share, "params", "imu.yaml") + e_comms_yaml = os.path.join(pkg_share, "params", "e_comms.yaml") + + sim_mode = LaunchConfiguration("simulation_mode") + + return LaunchDescription( + [ + DeclareLaunchArgument("simulation_mode", default_value="false"), + GroupAction( + [ + SetParametersFromFile(system_yaml), + SetParameter(name="simulation_mode", value=sim_mode), + Node( + package="autonomous_kart", + executable="camera_node", + name="camera_node", + parameters=[camera_yaml], + ), + Node( + package="autonomous_kart", + executable="pathfinder_node", + name="pathfinder_node", + parameters=[pathfinder_yaml, safety_yaml], + ), + Node( + package="autonomous_kart", + executable="opencv_pathfinder_node", + name="opencv_pathfinder_node", + parameters=[gps_yaml], + ), + Node( + package="autonomous_kart", + executable="master_api", + name="master_api", + ), + Node( + package="autonomous_kart", + executable="localization_node", + name="localization_node", + parameters=[pathfinder_yaml, localization_yaml], + ), + Node( + package="autonomous_kart", + executable="e_comms_node", + name="e_comms_node", + parameters=[e_comms_yaml], + ), + Node( + package="autonomous_kart", + executable="gps_node", + name="gps_node", + parameters=[gps_yaml], + ), + Node( + package="autonomous_kart", + executable="imu_node", + name="imu_node", + parameters=[imu_yaml], + ), + ] + ), + ] + ) diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py new file mode 100644 index 00000000..8c69847e --- /dev/null +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py @@ -0,0 +1,32 @@ +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument, GroupAction +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node, SetParameter, SetParametersFromFile +from ament_index_python.packages import get_package_share_directory +import os + + +def generate_launch_description(): + pkg_share = get_package_share_directory("autonomous_kart") + + system_yaml = os.path.join(pkg_share, "params", "system.yaml") + + sim_mode = LaunchConfiguration("simulation_mode") + + return LaunchDescription( + [ + DeclareLaunchArgument("simulation_mode", default_value="false"), + GroupAction( + [ + SetParametersFromFile(system_yaml), + SetParameter(name="simulation_mode", value=sim_mode), + + Node( + package="autonomous_kart", + executable="metrics_node", + name="metrics_node", + ), + ] + ), + ] + ) From 13cbbb45d480ebcabd653128e55e29a6302387f9 Mon Sep 17 00:00:00 2001 From: shb-png Date: Thu, 14 May 2026 15:09:29 +0000 Subject: [PATCH 02/35] ignore logs --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 2734fac9..a054c13f 100644 --- a/.gitignore +++ b/.gitignore @@ -176,4 +176,6 @@ cython_debug/ # Ros build ignored install log +logs +kart_logs build From 50476aa78d5b5a2598848f0777702747357a985d Mon Sep 17 00:00:00 2001 From: shb-png Date: Thu, 14 May 2026 18:51:17 +0000 Subject: [PATCH 03/35] move rosbags to exclusively rubik bringup --- scripts/start.bash | 20 +---------------- .../launch/bringup_rubik.launch.py | 22 ++++++++++++++++--- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/scripts/start.bash b/scripts/start.bash index af0722e6..e73cf390 100755 --- a/scripts/start.bash +++ b/scripts/start.bash @@ -9,22 +9,4 @@ pkill -f master_api || true # Lat/long are approx west lafayette, not important to be highly accurate mkdir -p /ws/logs -str2str -in ntrip://shayman1:shayman1@108.59.49.226:9000/MSM4_VRS -out tcpsvr://:9195 -b 1 -p 40.4376975222 -86.9444409756 200 >> /ws/logs/str2str.log 2>&1 & - -# Logs supervisor - crash tolerant -( - while true; do - RUN_NAME="run_$(date -u +%Y%m%d_%H%M%S)" - ros2 bag record -a \ - --storage mcap \ - --storage-preset-profile zstd_fast \ - --max-bag-duration 60 \ - --exclude '/camera/.*' \ - --output "/ws/logs/$RUN_NAME" \ - >> /ws/logs/recorder.log 2>&1 - echo "[$(date -u +%FT%TZ)] recorder exited, restarting in 1s" >> /ws/logs/recorder.log - sleep 1 - done -) & - -sleep infinity \ No newline at end of file +str2str -in ntrip://shayman1:shayman1@108.59.49.226:9000/MSM4_VRS -out tcpsvr://:9195 -b 1 -p 40.4376975222 -86.9444409756 200 >> /ws/logs/str2str.log 2>&1 & \ No newline at end of file diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py index 8c69847e..58a3190a 100644 --- a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py @@ -1,17 +1,31 @@ from launch import LaunchDescription -from launch.actions import DeclareLaunchArgument, GroupAction +from launch.actions import DeclareLaunchArgument, GroupAction, ExecuteProcess from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node, SetParameter, SetParametersFromFile from ament_index_python.packages import get_package_share_directory +from datetime import datetime import os def generate_launch_description(): pkg_share = get_package_share_directory("autonomous_kart") - system_yaml = os.path.join(pkg_share, "params", "system.yaml") - + run_name = datetime.now().strftime("run_%Y%m%d_%H%M%S") + bag_output_path = os.path.join("/ws/logs", run_name) sim_mode = LaunchConfiguration("simulation_mode") + rosbag_recorder = ExecuteProcess( + cmd=[ + 'ros2', 'bag', 'record', '-a', + '--storage', 'mcap', + '--storage-preset-profile', 'zstd_fast', + '--max-bag-duration', '60', + '--exclude', '/camera/.*', + '--output', bag_output_path + ], + output='screen', + respawn=True, + respawn_delay=1.0 + ) return LaunchDescription( [ @@ -21,6 +35,8 @@ def generate_launch_description(): SetParametersFromFile(system_yaml), SetParameter(name="simulation_mode", value=sim_mode), + rosbag_recorder, + Node( package="autonomous_kart", executable="metrics_node", From 8926fdd9ab4bf5825506be9d6044ea01e9711294 Mon Sep 17 00:00:00 2001 From: shb-png Date: Thu, 14 May 2026 15:05:48 -0400 Subject: [PATCH 04/35] ROS_LOCALHOST_ONLY = 0 --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 36a8b6e3..198b41ad 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -7,7 +7,7 @@ "workspaceFolder": "/ws", "containerEnv": { "ROS_DOMAIN_ID": "42", - "ROS_LOCALHOST_ONLY": "1", + "ROS_LOCALHOST_ONLY": "0", "CYCLONEDDS_URI": "file:///ws/docker/cyclonedds.xml" }, "customizations": { From 604fa22bf341411b839743feb03a0e11f3c05e40 Mon Sep 17 00:00:00 2001 From: shb-png Date: Thu, 14 May 2026 15:54:01 -0400 Subject: [PATCH 05/35] idk --- .devcontainer/devcontainer.json | 2 +- scripts/start.bash | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 198b41ad..36a8b6e3 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -7,7 +7,7 @@ "workspaceFolder": "/ws", "containerEnv": { "ROS_DOMAIN_ID": "42", - "ROS_LOCALHOST_ONLY": "0", + "ROS_LOCALHOST_ONLY": "1", "CYCLONEDDS_URI": "file:///ws/docker/cyclonedds.xml" }, "customizations": { diff --git a/scripts/start.bash b/scripts/start.bash index e73cf390..c2fa9a27 100755 --- a/scripts/start.bash +++ b/scripts/start.bash @@ -9,4 +9,6 @@ pkill -f master_api || true # Lat/long are approx west lafayette, not important to be highly accurate mkdir -p /ws/logs -str2str -in ntrip://shayman1:shayman1@108.59.49.226:9000/MSM4_VRS -out tcpsvr://:9195 -b 1 -p 40.4376975222 -86.9444409756 200 >> /ws/logs/str2str.log 2>&1 & \ No newline at end of file +str2str -in ntrip://shayman1:shayman1@108.59.49.226:9000/MSM4_VRS -out tcpsvr://:9195 -b 1 -p 40.4376975222 -86.9444409756 200 >> /ws/logs/str2str.log 2>&1 & + +sleep infinity \ No newline at end of file From d5d31a9be58026fbace0ffa76479080e50e620e6 Mon Sep 17 00:00:00 2001 From: shb-png Date: Thu, 14 May 2026 19:57:35 +0000 Subject: [PATCH 06/35] idk --- .devcontainer/devcontainer.json | 2 +- compose/docker-compose.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 36a8b6e3..198b41ad 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -7,7 +7,7 @@ "workspaceFolder": "/ws", "containerEnv": { "ROS_DOMAIN_ID": "42", - "ROS_LOCALHOST_ONLY": "1", + "ROS_LOCALHOST_ONLY": "0", "CYCLONEDDS_URI": "file:///ws/docker/cyclonedds.xml" }, "customizations": { diff --git a/compose/docker-compose.yml b/compose/docker-compose.yml index e2530e7c..8e5ec688 100644 --- a/compose/docker-compose.yml +++ b/compose/docker-compose.yml @@ -7,11 +7,11 @@ services: volumes: - ../:/ws - ros_cache:/root/.cache - - /data/kart_logs:/ws/logs # logs location + - ../data/kart_logs:/ws/logs # logs location environment: - ROS_DISTRO=humble - ROS_DOMAIN_ID=42 - - ROS_LOCALHOST_ONLY=1 + - ROS_LOCALHOST_ONLY=0 - CYCLONEDDS_URI=file:///ws/docker/cyclonedds.xml ports: - "8000:8000" From 0883be8bd346bde3b139856e795c4a5f908908bf Mon Sep 17 00:00:00 2001 From: shb-png Date: Thu, 14 May 2026 20:14:27 +0000 Subject: [PATCH 07/35] remote jetson launch --- .../launch/bringup_rubik.launch.py | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py index 58a3190a..3fb3ca1b 100644 --- a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py @@ -10,9 +10,11 @@ def generate_launch_description(): pkg_share = get_package_share_directory("autonomous_kart") system_yaml = os.path.join(pkg_share, "params", "system.yaml") + sim_mode = LaunchConfiguration("simulation_mode") + + # rosbag recording run_name = datetime.now().strftime("run_%Y%m%d_%H%M%S") bag_output_path = os.path.join("/ws/logs", run_name) - sim_mode = LaunchConfiguration("simulation_mode") rosbag_recorder = ExecuteProcess( cmd=[ 'ros2', 'bag', 'record', '-a', @@ -26,6 +28,24 @@ def generate_launch_description(): respawn=True, respawn_delay=1.0 ) + + # remote launch on jetson + jetson_ip = "0.0.0.0" # have to set static ip on jetson + jetson_user = "evc" # jetson username + + # pull --> build --> launch + remote_command = ( + "git pull && " + "source /opt/ros/humble/setup.bash &&" + "colcon build && " + "ros2 launch autonomous_kart jetson_bringup.launch.py" + ) + + launch_jetson = ExecuteProcess( + cmd=['ssh', f'{jetson_user}@{jetson_ip}', f'bash -l -c "{remote_command}"'], + output='screen', + shell=True + ) return LaunchDescription( [ @@ -44,5 +64,6 @@ def generate_launch_description(): ), ] ), + launch_jetson, ] ) From 5703db4a466dd36b4db4f09a6325e8743caa6227 Mon Sep 17 00:00:00 2001 From: shb-png Date: Thu, 14 May 2026 22:02:30 +0000 Subject: [PATCH 08/35] master api endpoints for jetson launch --- compose/docker-compose.yml | 3 +- scripts/start.bash | 20 +++++++++- .../launch/bringup_rubik.launch.py | 38 ------------------- .../nodes/master/master_api.py | 9 +++++ .../nodes/master/master_node.py | 21 ++++++++++ .../autonomous_kart/params/system.yaml | 2 + 6 files changed, 52 insertions(+), 41 deletions(-) diff --git a/compose/docker-compose.yml b/compose/docker-compose.yml index 8e5ec688..fc04eb93 100644 --- a/compose/docker-compose.yml +++ b/compose/docker-compose.yml @@ -7,11 +7,12 @@ services: volumes: - ../:/ws - ros_cache:/root/.cache - - ../data/kart_logs:/ws/logs # logs location + - /data/kart_logs:/ws/logs # logs location environment: - ROS_DISTRO=humble - ROS_DOMAIN_ID=42 - ROS_LOCALHOST_ONLY=0 + - TARGET_DEVICE=jetson # set target device for build (ex: jetson, rubik) - CYCLONEDDS_URI=file:///ws/docker/cyclonedds.xml ports: - "8000:8000" diff --git a/scripts/start.bash b/scripts/start.bash index c2fa9a27..bb047013 100755 --- a/scripts/start.bash +++ b/scripts/start.bash @@ -7,8 +7,24 @@ source /opt/ros/humble/setup.bash colcon build pkill -f master_api || true -# Lat/long are approx west lafayette, not important to be highly accurate mkdir -p /ws/logs -str2str -in ntrip://shayman1:shayman1@108.59.49.226:9000/MSM4_VRS -out tcpsvr://:9195 -b 1 -p 40.4376975222 -86.9444409756 200 >> /ws/logs/str2str.log 2>&1 & +if [ "$TARGET_DEVICE" == "jetson" ]; then + # Lat/long are approx west lafayette, not important to be highly accurate + str2str -in ntrip://shayman1:shayman1@108.59.49.226:9000/MSM4_VRS -out tcpsvr://:9195 -b 1 -p 40.4376975222 -86.9444409756 200 >> /ws/logs/str2str.log 2>&1 & +elif [ "$TARGET_DEVICE" == "rubik" ]; then + ( + while true; do + RUN_NAME="run_$(date -u +%Y%m%d_%H%M%S)" + ros2 bag record -a \ + --storage mcap \ + --storage-preset-profile zstd_fast \ + --max-bag-duration 60 \ + --exclude '/camera/.*' \ + --output "/ws/logs/$RUN_NAME" \ + >> /ws/logs/recorder.log 2>&1 + echo "[$(date -u +%FT%TZ)] recorder exited, restarting in 1s" >> /ws/logs/recorder.log + sleep 1 + done + ) & sleep infinity \ No newline at end of file diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py index 3fb3ca1b..d00b71d2 100644 --- a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py @@ -12,41 +12,6 @@ def generate_launch_description(): system_yaml = os.path.join(pkg_share, "params", "system.yaml") sim_mode = LaunchConfiguration("simulation_mode") - # rosbag recording - run_name = datetime.now().strftime("run_%Y%m%d_%H%M%S") - bag_output_path = os.path.join("/ws/logs", run_name) - rosbag_recorder = ExecuteProcess( - cmd=[ - 'ros2', 'bag', 'record', '-a', - '--storage', 'mcap', - '--storage-preset-profile', 'zstd_fast', - '--max-bag-duration', '60', - '--exclude', '/camera/.*', - '--output', bag_output_path - ], - output='screen', - respawn=True, - respawn_delay=1.0 - ) - - # remote launch on jetson - jetson_ip = "0.0.0.0" # have to set static ip on jetson - jetson_user = "evc" # jetson username - - # pull --> build --> launch - remote_command = ( - "git pull && " - "source /opt/ros/humble/setup.bash &&" - "colcon build && " - "ros2 launch autonomous_kart jetson_bringup.launch.py" - ) - - launch_jetson = ExecuteProcess( - cmd=['ssh', f'{jetson_user}@{jetson_ip}', f'bash -l -c "{remote_command}"'], - output='screen', - shell=True - ) - return LaunchDescription( [ DeclareLaunchArgument("simulation_mode", default_value="false"), @@ -55,8 +20,6 @@ def generate_launch_description(): SetParametersFromFile(system_yaml), SetParameter(name="simulation_mode", value=sim_mode), - rosbag_recorder, - Node( package="autonomous_kart", executable="metrics_node", @@ -64,6 +27,5 @@ def generate_launch_description(): ), ] ), - launch_jetson, ] ) diff --git a/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py b/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py index 102d5e0e..655bc9f5 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py +++ b/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py @@ -191,6 +191,15 @@ def lines_endpoint(): "static": static_xy, "dynamic": master_node.get_dynamic_line(), }) + +@app.route("/jetson/start", methods=["POST"]) +def jetson_start(): + if not master_node: + return jsonify({"error": "not initialized"}), 500 + + master_node.start_jetson() + + return True, "jetson launch started" def start(node: MasterNode) -> None: diff --git a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py index 3a1bec37..717ab68d 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py +++ b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py @@ -1,6 +1,7 @@ import json import threading import time +import subprocess from enum import Enum import math @@ -35,6 +36,8 @@ def __init__(self): self.yaw_cal_tick_dt = self.get_parameter("yaw_cal_tick_dt").value self.yaw_cal_accel_floor = self.get_parameter("yaw_cal_accel_floor").value self.yaw_cal_min_samples = self.get_parameter("yaw_cal_min_samples").value + self.jetson_ip = self.get_parameter("jetson_ip").value + self.jetson_user = self.get_parameter("jetson_username").value assert self.state in [s.value for s in STATES] @@ -331,6 +334,24 @@ def get_gps_status(self): with self._lock: return dict(self.gps_status_data) + def start_jetson(self): + with self._lock: + remote_command = ( + "bash ~/run_remote.sh --update" + ) + + ssh_command = [ + "ssh", + "-t", + f"{self.jetson_user}@{self.jetson_ip}", + remote_command, + ] + + self.logger.info("Starting Jetson bringup...") + + subprocess.Popen([ + ssh_command, + ]) def main(args=None): rclpy.init(args=args) diff --git a/src/autonomous_kart/autonomous_kart/params/system.yaml b/src/autonomous_kart/autonomous_kart/params/system.yaml index e0a7ca61..7b55e1d2 100644 --- a/src/autonomous_kart/autonomous_kart/params/system.yaml +++ b/src/autonomous_kart/autonomous_kart/params/system.yaml @@ -5,3 +5,5 @@ system_state: "IDLE" # "STOPPED", "IDLE", "MANUAL", "AUTONOMOUS" system_frequency: 60 # Speed of hot loop (Hertz) line_path: "/ws/data/racing_line/line14.csv" + jetson_ip: "0.0.0.0" + jetson_username: "evc" \ No newline at end of file From 1d46025f2ca3ee33ed41192b03e76899a791a4db Mon Sep 17 00:00:00 2001 From: shb-png Date: Fri, 15 May 2026 01:48:21 +0000 Subject: [PATCH 09/35] jetson tailscape addr --- src/autonomous_kart/autonomous_kart/params/system.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autonomous_kart/autonomous_kart/params/system.yaml b/src/autonomous_kart/autonomous_kart/params/system.yaml index 7b55e1d2..d7b29ae2 100644 --- a/src/autonomous_kart/autonomous_kart/params/system.yaml +++ b/src/autonomous_kart/autonomous_kart/params/system.yaml @@ -5,5 +5,5 @@ system_state: "IDLE" # "STOPPED", "IDLE", "MANUAL", "AUTONOMOUS" system_frequency: 60 # Speed of hot loop (Hertz) line_path: "/ws/data/racing_line/line14.csv" - jetson_ip: "0.0.0.0" + jetson_ip: "evc-jetson.tail73145c.ts.net" jetson_username: "evc" \ No newline at end of file From ddf8bf33e28b74f0912586b88f3ef2b428fe791b Mon Sep 17 00:00:00 2001 From: shb-png Date: Fri, 15 May 2026 02:09:46 +0000 Subject: [PATCH 10/35] Add master_api node to bringup_rubik launch file --- .../autonomous_kart/launch/bringup_rubik.launch.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py index d00b71d2..3fb824b8 100644 --- a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py @@ -25,6 +25,12 @@ def generate_launch_description(): executable="metrics_node", name="metrics_node", ), + Node( + package="autonomous_kart", + executable="master_api", + name="master_api", + parameters=[system_yaml], + ), ] ), ] From 0d3ef44aee45fe90398b7ca02596d909f0b16a08 Mon Sep 17 00:00:00 2001 From: shb-png Date: Fri, 15 May 2026 02:14:42 +0000 Subject: [PATCH 11/35] pls work --- .../autonomous_kart/nodes/master/master_node.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py index 717ab68d..ff8d969d 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py +++ b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py @@ -349,9 +349,7 @@ def start_jetson(self): self.logger.info("Starting Jetson bringup...") - subprocess.Popen([ - ssh_command, - ]) + subprocess.Popen(ssh_command) def main(args=None): rclpy.init(args=args) From 0cc69162c41585a07efb8d0a44d1f54f4985bc01 Mon Sep 17 00:00:00 2001 From: shb-png Date: Fri, 15 May 2026 02:16:39 +0000 Subject: [PATCH 12/35] ssh --- docker/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index eca954a4..5b5141f7 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -20,6 +20,7 @@ RUN apt-get -o Acquire::http::Pipeline-Depth="0" \ ros-${ROS_DISTRO}-rclpy ros-${ROS_DISTRO}-ros2bag \ ros-${ROS_DISTRO}-tf2-tools ros-${ROS_DISTRO}-image-transport \ ros-${ROS_DISTRO}-cv-bridge \ + openssh-client \ git curl nano \ socat rtklib i2c-tools && \ rm -rf /var/lib/apt/lists/* From 9bc8d0d0fc38b4444576812fe67c2952e2c3974c Mon Sep 17 00:00:00 2001 From: shb-png Date: Fri, 15 May 2026 02:30:52 +0000 Subject: [PATCH 13/35] jsonify it!! --- .../autonomous_kart/nodes/master/master_api.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py b/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py index 655bc9f5..7a171b4e 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py +++ b/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py @@ -199,7 +199,9 @@ def jetson_start(): master_node.start_jetson() - return True, "jetson launch started" + return jsonify({ + "message": "jetson launch started" + }) def start(node: MasterNode) -> None: From d770149d6bf67efd43defc92eaa852d703afb630 Mon Sep 17 00:00:00 2001 From: shb-png Date: Fri, 15 May 2026 03:04:09 +0000 Subject: [PATCH 14/35] restart and update jetston endpoint --- .../nodes/master/master_api.py | 18 +++++++++-- .../nodes/master/master_node.py | 31 +++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py b/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py index 7a171b4e..a0f3f5c0 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py +++ b/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py @@ -192,15 +192,27 @@ def lines_endpoint(): "dynamic": master_node.get_dynamic_line(), }) -@app.route("/jetson/start", methods=["POST"]) +@app.route("/jetson/restart", methods=["POST"]) def jetson_start(): if not master_node: return jsonify({"error": "not initialized"}), 500 - master_node.start_jetson() + master_node.restart_jetson() return jsonify({ - "message": "jetson launch started" + "message": "jetson restart started" + }) + + +@app.route("/jetson/update", methods=["POST"]) +def jetson_update(): + if not master_node: + return jsonify({"error": "not initialized"}), 500 + + master_node.update_jetson() + + return jsonify({ + "message": "jetson update started" }) diff --git a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py index ff8d969d..2f29f2cd 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py +++ b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py @@ -334,7 +334,8 @@ def get_gps_status(self): with self._lock: return dict(self.gps_status_data) - def start_jetson(self): + # pull latest code, rebuild container, and restart bringup on jetson + def restart_jetson(self): with self._lock: remote_command = ( "bash ~/run_remote.sh --update" @@ -347,7 +348,33 @@ def start_jetson(self): remote_command, ] - self.logger.info("Starting Jetson bringup...") + self.logger.info("Rebuilding Jetson container and pulling latest code...") + + subprocess.Popen(ssh_command) + + # only pull latest code, dont rebuild container + def update_jetson(self): + with self._lock: + remote_command = ( + "cd ~/AutonomousKart && " + "git pull && " + "docker exec ros2-dev bash -lc '" + "source /opt/ros/humble/setup.bash && " + "cd /ws && " + "colcon build --symlink-install && " + "source install/setup.bash && " + "ros2 launch autonomous_kart bringup_jetson.launch.py" + "'" + ) + + ssh_command = [ + "ssh", + "-t", + f"{self.jetson_user}@{self.jetson_ip}", + remote_command, + ] + + self.logger.info("Starting Jetson and pulling latest code...") subprocess.Popen(ssh_command) From ed2cf21a05c9036fd76ba437a85166ba4e7d00dc Mon Sep 17 00:00:00 2001 From: shb-png Date: Fri, 15 May 2026 12:32:42 -0400 Subject: [PATCH 15/35] remove --symlink-install from colcon build --- src/autonomous_kart/autonomous_kart/nodes/master/master_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py index 2f29f2cd..9914ec5b 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py +++ b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py @@ -361,7 +361,7 @@ def update_jetson(self): "docker exec ros2-dev bash -lc '" "source /opt/ros/humble/setup.bash && " "cd /ws && " - "colcon build --symlink-install && " + "colcon build && " "source install/setup.bash && " "ros2 launch autonomous_kart bringup_jetson.launch.py" "'" From 41813af7ca774f67c2df9069b6db1db008ae1193 Mon Sep 17 00:00:00 2001 From: shb-png Date: Fri, 15 May 2026 13:13:54 -0400 Subject: [PATCH 16/35] copilot comments --- scripts/start.bash | 1 + .../nodes/master/master_api.py | 26 ++++++- .../nodes/master/master_node.py | 78 +++++++++---------- 3 files changed, 65 insertions(+), 40 deletions(-) diff --git a/scripts/start.bash b/scripts/start.bash index bb047013..9ca04e74 100755 --- a/scripts/start.bash +++ b/scripts/start.bash @@ -27,4 +27,5 @@ elif [ "$TARGET_DEVICE" == "rubik" ]; then sleep 1 done ) & +fi sleep infinity \ No newline at end of file diff --git a/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py b/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py index a0f3f5c0..473572f4 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py +++ b/src/autonomous_kart/autonomous_kart/nodes/master/master_api.py @@ -192,8 +192,20 @@ def lines_endpoint(): "dynamic": master_node.get_dynamic_line(), }) +@app.route("/jetson/hotswap", methods=["POST"]) +def jetson_hotswap(): + if not master_node: + return jsonify({"error": "not initialized"}), 500 + + master_node.hotswap_jetson() + + return jsonify({ + "message": "jetson hotswap started" + }) + + @app.route("/jetson/restart", methods=["POST"]) -def jetson_start(): +def jetson_restart(): if not master_node: return jsonify({"error": "not initialized"}), 500 @@ -216,6 +228,18 @@ def jetson_update(): }) +@app.route("/jetson/rebuild", methods=["POST"]) +def jetson_rebuild(): + if not master_node: + return jsonify({"error": "not initialized"}), 500 + + master_node.rebuild_jetson() + + return jsonify({ + "message": "jetson rebuild started" + }) + + def start(node: MasterNode) -> None: try: rclpy.spin(node) diff --git a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py index 9914ec5b..4dcd26c2 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py +++ b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py @@ -334,49 +334,49 @@ def get_gps_status(self): with self._lock: return dict(self.gps_status_data) - # pull latest code, rebuild container, and restart bringup on jetson - def restart_jetson(self): - with self._lock: - remote_command = ( - "bash ~/run_remote.sh --update" - ) - - ssh_command = [ - "ssh", - "-t", - f"{self.jetson_user}@{self.jetson_ip}", - remote_command, - ] - - self.logger.info("Rebuilding Jetson container and pulling latest code...") + # Jetson remote management + + def _ssh_fire(self, remote_command: str, log_msg: str): + """Shared helper: open a non-blocking SSH subprocess to the Jetson.""" + ssh_command = [ + "ssh", "-t", + f"{self.jetson_user}@{self.jetson_ip}", + remote_command, + ] + self.logger.info(log_msg) + subprocess.Popen(ssh_command) + + def hotswap_jetson(self): + """Git-pull and rebuild inside the *running* container, then relaunch bringup_rubik. + The container is never stopped — fastest way to pick up new code mid-session.""" + self._ssh_fire( + "bash ~/run_remote.sh --hotswap", + "Hotswapping: pulling latest code and relaunching inside running container...", + ) - subprocess.Popen(ssh_command) + def restart_jetson(self): + """Stop the container, rebuild the ROS workspace, and relaunch bringup. + No git pull, no Docker image pull — fastest way to bounce the stack.""" + self._ssh_fire( + "bash ~/run_remote.sh --restart", + "Restarting Jetson container (no code update)...", + ) - # only pull latest code, dont rebuild container def update_jetson(self): - with self._lock: - remote_command = ( - "cd ~/AutonomousKart && " - "git pull && " - "docker exec ros2-dev bash -lc '" - "source /opt/ros/humble/setup.bash && " - "cd /ws && " - "colcon build && " - "source install/setup.bash && " - "ros2 launch autonomous_kart bringup_jetson.launch.py" - "'" - ) - - ssh_command = [ - "ssh", - "-t", - f"{self.jetson_user}@{self.jetson_ip}", - remote_command, - ] - - self.logger.info("Starting Jetson and pulling latest code...") + """Git-pull the latest code, then restart. + Use this before a session to pick up new commits without a full image rebuild.""" + self._ssh_fire( + "bash ~/run_remote.sh --update", + "Pulling latest code and restarting Jetson...", + ) - subprocess.Popen(ssh_command) + def rebuild_jetson(self): + """Pull the latest Docker image, git-pull code, then restart. + Use this after a Docker image has been pushed (e.g. new deps or base OS change).""" + self._ssh_fire( + "bash ~/run_remote.sh --rebuild", + "Pulling latest Docker image + code and rebuilding Jetson...", + ) def main(args=None): rclpy.init(args=args) From d37d01391151431c172523b0fb518f105709e18e Mon Sep 17 00:00:00 2001 From: shb-png Date: Fri, 15 May 2026 13:59:16 -0400 Subject: [PATCH 17/35] auto accept host key --- .../autonomous_kart/nodes/master/master_node.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py index 4dcd26c2..700c0b7a 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py +++ b/src/autonomous_kart/autonomous_kart/nodes/master/master_node.py @@ -339,10 +339,13 @@ def get_gps_status(self): def _ssh_fire(self, remote_command: str, log_msg: str): """Shared helper: open a non-blocking SSH subprocess to the Jetson.""" ssh_command = [ - "ssh", "-t", - f"{self.jetson_user}@{self.jetson_ip}", - remote_command, - ] + "ssh", "-t", + "-o", "StrictHostKeyChecking=no", + "-o", "UserKnownHostsFile=/dev/null", + f"{self.jetson_user}@{self.jetson_ip}", + remote_command, + ] + self.logger.info(log_msg) subprocess.Popen(ssh_command) From a3b3f5a1170cc3b28013efb63bb34c7a55ce3425 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 00:37:29 +0000 Subject: [PATCH 18/35] Move camera node to Rubik --- .../autonomous_kart/launch/bringup_jetson.launch.py | 7 ------- .../autonomous_kart/launch/bringup_rubik.launch.py | 9 +++++++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py index b63d91cd..1bf5d556 100644 --- a/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py @@ -9,7 +9,6 @@ def generate_launch_description(): pkg_share = get_package_share_directory("autonomous_kart") - camera_yaml = os.path.join(pkg_share, "params", "camera.yaml") gps_yaml = os.path.join(pkg_share, "params", "gps.yaml") safety_yaml = os.path.join(pkg_share, "params", "safety.yaml") system_yaml = os.path.join(pkg_share, "params", "system.yaml") @@ -27,12 +26,6 @@ def generate_launch_description(): [ SetParametersFromFile(system_yaml), SetParameter(name="simulation_mode", value=sim_mode), - Node( - package="autonomous_kart", - executable="camera_node", - name="camera_node", - parameters=[camera_yaml], - ), Node( package="autonomous_kart", executable="pathfinder_node", diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py index 3fb824b8..dc258c42 100644 --- a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py @@ -9,7 +9,10 @@ def generate_launch_description(): pkg_share = get_package_share_directory("autonomous_kart") + + camera_yaml = os.path.join(pkg_share, "params", "camera.yaml") system_yaml = os.path.join(pkg_share, "params", "system.yaml") + sim_mode = LaunchConfiguration("simulation_mode") return LaunchDescription( @@ -20,6 +23,12 @@ def generate_launch_description(): SetParametersFromFile(system_yaml), SetParameter(name="simulation_mode", value=sim_mode), + Node( + package="autonomous_kart", + executable="camera_node", + name="camera_node", + parameters=[camera_yaml], + ), Node( package="autonomous_kart", executable="metrics_node", From c9624172c8044eb2327be5436bff242881f63d94 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 00:38:24 +0000 Subject: [PATCH 19/35] Don't use metrics node --- .../autonomous_kart/launch/bringup_rubik.launch.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py index dc258c42..a99129c8 100644 --- a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py @@ -29,11 +29,6 @@ def generate_launch_description(): name="camera_node", parameters=[camera_yaml], ), - Node( - package="autonomous_kart", - executable="metrics_node", - name="metrics_node", - ), Node( package="autonomous_kart", executable="master_api", From e3229991801e296a91fa2153393a235353be90c1 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 00:42:35 +0000 Subject: [PATCH 20/35] Don't start master api on both --- .../autonomous_kart/launch/bringup_rubik.launch.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py index a99129c8..69dc500e 100644 --- a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py @@ -29,12 +29,6 @@ def generate_launch_description(): name="camera_node", parameters=[camera_yaml], ), - Node( - package="autonomous_kart", - executable="master_api", - name="master_api", - parameters=[system_yaml], - ), ] ), ] From 62079084d4194f47cc08a9fc9ffe7f5b6ae4b7ff Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 01:28:08 +0000 Subject: [PATCH 21/35] Docker compose service per target --- compose/docker-compose.yml | 78 +++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/compose/docker-compose.yml b/compose/docker-compose.yml index fc04eb93..b5508538 100644 --- a/compose/docker-compose.yml +++ b/compose/docker-compose.yml @@ -1,31 +1,55 @@ version: "3.8" + +x-dev-base: &dev-base + image: ghcr.io/evc-purdue/ros2-humble-dev:main + + network_mode: host + + stdin_open: true + tty: true + + volumes: + - ../:/ws + - ros_cache:/root/.cache + + environment: + - ROS_DISTRO=humble + - ROS_DOMAIN_ID=42 + - ROS_LOCALHOST_ONLY=0 + - RMW_IMPLEMENTATION=rmw_cyclonedds_cpp + - CYCLONEDDS_URI=file:///ws/docker/cyclonedds.xml + + command: bash /ws/scripts/start.bash + services: - dev: - image: ghcr.io/evc-purdue/ros2-humble-dev:main - container_name: ros2-dev - hostname: ros2-dev - volumes: - - ../:/ws - - ros_cache:/root/.cache - - /data/kart_logs:/ws/logs # logs location + + dev-jetson: + <<: *dev-base + + container_name: ros2-dev-jetson + hostname: jetson-dev + environment: - - ROS_DISTRO=humble - - ROS_DOMAIN_ID=42 - - ROS_LOCALHOST_ONLY=0 - - TARGET_DEVICE=jetson # set target device for build (ex: jetson, rubik) - - CYCLONEDDS_URI=file:///ws/docker/cyclonedds.xml - ports: - - "8000:8000" -# devices: -# - "/dev/ttyACM0:/dev/ttyACM0" -# - "/dev/ttyTHS1:/dev/ttyTHS1" # GPS -# - "/dev/i2c-7:/dev/i2c-7" -# - "/dev/spidev12.0:/dev/spidev12.0" # SPI bus 12, CS0 -# - "/dev/video0:/dev/video0" - stdin_open: true - tty: true - restart: always - command: bash /ws/scripts/start.bash - network_mode: host + - TARGET_DEVICE=jetson + - ROS_NETWORK_INTERFACE=enP8p1s0 + + # devices: + # - "/dev/ttyACM0:/dev/ttyACM0" # canable + # - "/dev/ttyTHS1:/dev/ttyTHS1" # GPS + # - "/dev/i2c-7:/dev/i2c-7" # IMU + + dev-rubik: + <<: *dev-base + + container_name: ros2-dev-rubik + hostname: rubik-dev + + environment: + - TARGET_DEVICE=rubik + - ROS_NETWORK_INTERFACE=enxf074e47f50f9 + + # devices: + # - "/dev/video0:/dev/video0" + volumes: - ros_cache: + ros_cache: \ No newline at end of file From 093309c4164f3678f81d5285c7c9dc34519dd3a4 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 01:28:28 +0000 Subject: [PATCH 22/35] Update devcontainer jsons --- .devcontainer/devcontainer.jetson.json | 43 +++++++++++++++++++ ...devcontainer.json => devcontainer.pi.json} | 13 +++++- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 .devcontainer/devcontainer.jetson.json rename .devcontainer/{devcontainer.json => devcontainer.pi.json} (90%) diff --git a/.devcontainer/devcontainer.jetson.json b/.devcontainer/devcontainer.jetson.json new file mode 100644 index 00000000..d1adb667 --- /dev/null +++ b/.devcontainer/devcontainer.jetson.json @@ -0,0 +1,43 @@ +{ + "name": "ROS2 Jetson Dev", + + "dockerComposeFile": [ + "../compose/docker-compose.yml" + ], + + "service": "dev-jetson", + + "workspaceFolder": "/ws", + + "containerEnv": { + "ROS_DOMAIN_ID": "42", + "ROS_LOCALHOST_ONLY": "0", + "RMW_IMPLEMENTATION": "rmw_cyclonedds_cpp", + "CYCLONEDDS_URI": "file:///ws/docker/cyclonedds.xml" + }, + + "customizations": { + "vscode": { + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "ms-azuretools.vscode-docker", + "foxglove.vscode-foxglove" + ], + + "settings": { + "python.defaultInterpreterPath": "/ws/.venv/bin/python", + + "python.analysis.extraPaths": [ + "/ws/install", + "/opt/ros/humble/lib/python3.10/site-packages", + "/opt/ros/humble/local/lib/python3.10/dist-packages", + "/ws/install/lib/python3.10/site-packages" + ] + } + } + }, + + "postCreateCommand": "bash /ws/scripts/devcontainer_post_create.sh", + "postAttachCommand": "bash /ws/scripts/devcontainer_post_attach.sh" +} \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.pi.json similarity index 90% rename from .devcontainer/devcontainer.json rename to .devcontainer/devcontainer.pi.json index 198b41ad..426e8aad 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.pi.json @@ -1,15 +1,21 @@ { - "name": "ROS2 rclpy Dev", + "name": "ROS2 Pi Dev", + "dockerComposeFile": [ "../compose/docker-compose.yml" ], - "service": "dev", + + "service": "dev-pi", + "workspaceFolder": "/ws", + "containerEnv": { "ROS_DOMAIN_ID": "42", "ROS_LOCALHOST_ONLY": "0", + "RMW_IMPLEMENTATION": "rmw_cyclonedds_cpp", "CYCLONEDDS_URI": "file:///ws/docker/cyclonedds.xml" }, + "customizations": { "vscode": { "extensions": [ @@ -18,8 +24,10 @@ "ms-azuretools.vscode-docker", "foxglove.vscode-foxglove" ], + "settings": { "python.defaultInterpreterPath": "/ws/.venv/bin/python", + "python.analysis.extraPaths": [ "/ws/install", "/opt/ros/humble/lib/python3.10/site-packages", @@ -29,6 +37,7 @@ } } }, + "postCreateCommand": "bash /ws/scripts/devcontainer_post_create.sh", "postAttachCommand": "bash /ws/scripts/devcontainer_post_attach.sh" } \ No newline at end of file From aca85d0e02806d697acde03d69ad1382c7c474bb Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 01:28:49 +0000 Subject: [PATCH 23/35] CycloneDDS config to work over the network --- docker/cyclonedds.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docker/cyclonedds.xml b/docker/cyclonedds.xml index 22c864df..37b993e5 100644 --- a/docker/cyclonedds.xml +++ b/docker/cyclonedds.xml @@ -3,6 +3,14 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://cdds.io/config https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/etc/cyclonedds.xsd"> + + true + + + + + + auto 32 From 8f4de0053049328af7b9240f5fa0db187e230732 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 01:34:57 +0000 Subject: [PATCH 24/35] Rename pi to rubik --- .../{devcontainer.pi.json => devcontainer.rubik.json} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .devcontainer/{devcontainer.pi.json => devcontainer.rubik.json} (94%) diff --git a/.devcontainer/devcontainer.pi.json b/.devcontainer/devcontainer.rubik.json similarity index 94% rename from .devcontainer/devcontainer.pi.json rename to .devcontainer/devcontainer.rubik.json index 426e8aad..0a4e9a09 100644 --- a/.devcontainer/devcontainer.pi.json +++ b/.devcontainer/devcontainer.rubik.json @@ -1,11 +1,11 @@ { - "name": "ROS2 Pi Dev", + "name": "ROS2 Rubik Dev", "dockerComposeFile": [ "../compose/docker-compose.yml" ], - "service": "dev-pi", + "service": "dev-rubik", "workspaceFolder": "/ws", From ddfdfd034d0c041245d07613824b20bc51fc0c74 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 01:46:28 +0000 Subject: [PATCH 25/35] Hand merge the base compose more readable --- compose/docker-compose.yml | 63 ++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/compose/docker-compose.yml b/compose/docker-compose.yml index b5508538..e907e5f3 100644 --- a/compose/docker-compose.yml +++ b/compose/docker-compose.yml @@ -1,55 +1,60 @@ version: "3.8" -x-dev-base: &dev-base - image: ghcr.io/evc-purdue/ros2-humble-dev:main - - network_mode: host - - stdin_open: true - tty: true - - volumes: - - ../:/ws - - ros_cache:/root/.cache - - environment: - - ROS_DISTRO=humble - - ROS_DOMAIN_ID=42 - - ROS_LOCALHOST_ONLY=0 - - RMW_IMPLEMENTATION=rmw_cyclonedds_cpp - - CYCLONEDDS_URI=file:///ws/docker/cyclonedds.xml - - command: bash /ws/scripts/start.bash - services: dev-jetson: - <<: *dev-base - container_name: ros2-dev-jetson hostname: jetson-dev - environment: - TARGET_DEVICE=jetson - ROS_NETWORK_INTERFACE=enP8p1s0 - + - ROS_DISTRO=humble + - ROS_DOMAIN_ID=42 + - ROS_LOCALHOST_ONLY=0 + - RMW_IMPLEMENTATION=rmw_cyclonedds_cpp + - CYCLONEDDS_URI=file:///ws/docker/cyclonedds.xml # devices: # - "/dev/ttyACM0:/dev/ttyACM0" # canable # - "/dev/ttyTHS1:/dev/ttyTHS1" # GPS # - "/dev/i2c-7:/dev/i2c-7" # IMU + image: ghcr.io/evc-purdue/ros2-humble-dev:main + network_mode: host + stdin_open: true + tty: true + restart: always + volumes: + - ../:/ws + - ros_cache:/root/.cache + - /data/kart_logs:/ws/logs + ports: + - "8000:8000" + command: bash /ws/scripts/start.bash dev-rubik: - <<: *dev-base - container_name: ros2-dev-rubik hostname: rubik-dev - environment: - TARGET_DEVICE=rubik - ROS_NETWORK_INTERFACE=enxf074e47f50f9 - + - ROS_DISTRO=humble + - ROS_DOMAIN_ID=42 + - ROS_LOCALHOST_ONLY=0 + - RMW_IMPLEMENTATION=rmw_cyclonedds_cpp + - CYCLONEDDS_URI=file:///ws/docker/cyclonedds.xml # devices: # - "/dev/video0:/dev/video0" + image: ghcr.io/evc-purdue/ros2-humble-dev:main + network_mode: host + stdin_open: true + tty: true + restart: always + volumes: + - ../:/ws + - ros_cache:/root/.cache + - /data/kart_logs:/ws/logs + ports: + - "8000:8000" + command: bash /ws/scripts/start.bash volumes: ros_cache: \ No newline at end of file From ef68586a2623d6f6cb2845600ba5a84f0220cc58 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 02:11:33 +0000 Subject: [PATCH 26/35] Update quickstart --- docs/README/quickstart.md | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/README/quickstart.md b/docs/README/quickstart.md index d8890383..55ae54b4 100644 --- a/docs/README/quickstart.md +++ b/docs/README/quickstart.md @@ -19,9 +19,17 @@ ros2 launch autonomous_kart bringup_sim.launch.py sudo systemctl start docker ``` 2) Make container + +- JETSON ```bash -sudo docker compose -f compose/docker-compose.yml up -d dev +sudo docker compose -f compose/docker-compose.yml up -d dev-jetson ``` + +- RUBIK +```bash +sudo docker compose -f compose/docker-compose.yml up -d dev-rubik +``` + 3) Exec into container ```bash docker exec -it bash @@ -31,5 +39,26 @@ docker exec -it bash source /opt/ros/humble/setup.bash colcon build source install/setup.bash -ros2 launch autonomous_kart bringup_pi.launch.py +``` + +5) Launch + +- JETSON +```bash +ros2 launch autonomous_kart bringup_jetson.launch.py +``` + +- RUBIK +```bash +ros2 launch autonomous_kart bringup_rubik.launch.py +``` + +- ALL +```bash +ros2 launch autonomous_kart bringup_all.launch.py +``` + +- SIM +```bash +ros2 launch autonomous_kart bringup_sim.launch.py ``` \ No newline at end of file From 0ba8be0e3562150d4427ca9d1ea5741b287f121a Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 02:18:58 +0000 Subject: [PATCH 27/35] Update docs --- docs/README/quickstart.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/README/quickstart.md b/docs/README/quickstart.md index 55ae54b4..d0c80d75 100644 --- a/docs/README/quickstart.md +++ b/docs/README/quickstart.md @@ -31,9 +31,17 @@ sudo docker compose -f compose/docker-compose.yml up -d dev-rubik ``` 3) Exec into container + +- JETSON +```bash +docker exec -it ros2-dev-jetson bash +``` + +- RUBIK ```bash -docker exec -it bash +docker exec -it ros2-dev-rubik bash ``` + 4) Setup ROS ```bash source /opt/ros/humble/setup.bash @@ -56,9 +64,4 @@ ros2 launch autonomous_kart bringup_rubik.launch.py - ALL ```bash ros2 launch autonomous_kart bringup_all.launch.py -``` - -- SIM -```bash -ros2 launch autonomous_kart bringup_sim.launch.py ``` \ No newline at end of file From 404d2b082e6f4a53feea42372558e275b102d942 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 02:37:31 +0000 Subject: [PATCH 28/35] camera update --- src/autonomous_kart/autonomous_kart/nodes/camera/camera_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autonomous_kart/autonomous_kart/nodes/camera/camera_node.py b/src/autonomous_kart/autonomous_kart/nodes/camera/camera_node.py index f8514c34..cca97dad 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/camera/camera_node.py +++ b/src/autonomous_kart/autonomous_kart/nodes/camera/camera_node.py @@ -54,7 +54,7 @@ def __init__(self): raise RuntimeError(f"Failed to open video: {video_path}") else: - self.cap = cv2.VideoCapture(0) + self.cap = cv2.VideoCapture('/dev/video0') self.video_fps = self.fps if not self.cap.isOpened(): From 6aa876486f175e816f671542216b53d321874cd4 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 03:00:09 +0000 Subject: [PATCH 29/35] sudo --- docs/README/quickstart.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README/quickstart.md b/docs/README/quickstart.md index d0c80d75..1ed9d080 100644 --- a/docs/README/quickstart.md +++ b/docs/README/quickstart.md @@ -34,12 +34,12 @@ sudo docker compose -f compose/docker-compose.yml up -d dev-rubik - JETSON ```bash -docker exec -it ros2-dev-jetson bash +sudo docker exec -it ros2-dev-jetson bash ``` - RUBIK ```bash -docker exec -it ros2-dev-rubik bash +sudo docker exec -it ros2-dev-rubik bash ``` 4) Setup ROS From e40588f29e6bc1fae8d925bfbfe9e8a68af98a0c Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 03:00:15 +0000 Subject: [PATCH 30/35] info debug print --- src/autonomous_kart/autonomous_kart/nodes/camera/camera_node.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/autonomous_kart/autonomous_kart/nodes/camera/camera_node.py b/src/autonomous_kart/autonomous_kart/nodes/camera/camera_node.py index cca97dad..2c223d99 100644 --- a/src/autonomous_kart/autonomous_kart/nodes/camera/camera_node.py +++ b/src/autonomous_kart/autonomous_kart/nodes/camera/camera_node.py @@ -84,6 +84,7 @@ def timer_callback(self): self.logger.warning("No frame available") if publish_frame is not None: + self.logger.info(f"Publishing frame {self.frame_counter}") self.image_pub.publish(publish_frame) self.frame_counter += 1 From 8d07380c9c478fb7bfbe1ce30372a6c1b9a7a081 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 17:25:54 +0000 Subject: [PATCH 31/35] Use system level enviorment variables to revert back to one service this allows the same exact commands to be used on the jetson or rubik to launch the respective ones just need to make sure the variables are set on the jetson/rubik correctly --- compose/docker-compose.yml | 55 +++++++++----------------------------- 1 file changed, 12 insertions(+), 43 deletions(-) diff --git a/compose/docker-compose.yml b/compose/docker-compose.yml index e907e5f3..c4d88d88 100644 --- a/compose/docker-compose.yml +++ b/compose/docker-compose.yml @@ -1,60 +1,29 @@ version: "3.8" - services: - - dev-jetson: - container_name: ros2-dev-jetson - hostname: jetson-dev - environment: - - TARGET_DEVICE=jetson - - ROS_NETWORK_INTERFACE=enP8p1s0 - - ROS_DISTRO=humble - - ROS_DOMAIN_ID=42 - - ROS_LOCALHOST_ONLY=0 - - RMW_IMPLEMENTATION=rmw_cyclonedds_cpp - - CYCLONEDDS_URI=file:///ws/docker/cyclonedds.xml - # devices: - # - "/dev/ttyACM0:/dev/ttyACM0" # canable - # - "/dev/ttyTHS1:/dev/ttyTHS1" # GPS - # - "/dev/i2c-7:/dev/i2c-7" # IMU + dev: image: ghcr.io/evc-purdue/ros2-humble-dev:main - network_mode: host - stdin_open: true - tty: true - restart: always + container_name: ros2-dev + hostname: "${TARGET_DEVICE:-jetson}-dev" volumes: - ../:/ws - ros_cache:/root/.cache - - /data/kart_logs:/ws/logs - ports: - - "8000:8000" - command: bash /ws/scripts/start.bash - - dev-rubik: - container_name: ros2-dev-rubik - hostname: rubik-dev + - /data/kart_logs:/ws/logs # logs location environment: - - TARGET_DEVICE=rubik - - ROS_NETWORK_INTERFACE=enxf074e47f50f9 - ROS_DISTRO=humble - ROS_DOMAIN_ID=42 - ROS_LOCALHOST_ONLY=0 - - RMW_IMPLEMENTATION=rmw_cyclonedds_cpp - CYCLONEDDS_URI=file:///ws/docker/cyclonedds.xml - # devices: - # - "/dev/video0:/dev/video0" - image: ghcr.io/evc-purdue/ros2-humble-dev:main - network_mode: host + - TARGET_DEVICE=${TARGET_DEVICE:-jetson} + - ROS_NETWORK_INTERFACE=${ROS_NETWORK_INTERFACE:-enP8p1s0} +# devices: +# - "/dev/ttyACM0:/dev/ttyACM0" # canable +# - "/dev/ttyTHS1:/dev/ttyTHS1" # GPS +# - "/dev/i2c-7:/dev/i2c-7" # IMU +# - "/dev/video0:/dev/video0" # camera stdin_open: true tty: true restart: always - volumes: - - ../:/ws - - ros_cache:/root/.cache - - /data/kart_logs:/ws/logs - ports: - - "8000:8000" command: bash /ws/scripts/start.bash - + network_mode: host volumes: ros_cache: \ No newline at end of file From 2368bf3fc03564336f6902405f9c1c730b96b823 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 17:26:15 +0000 Subject: [PATCH 32/35] update docs --- docs/README/quickstart.md | 38 +++----------------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/docs/README/quickstart.md b/docs/README/quickstart.md index 1ed9d080..71bd8ecc 100644 --- a/docs/README/quickstart.md +++ b/docs/README/quickstart.md @@ -19,49 +19,17 @@ ros2 launch autonomous_kart bringup_sim.launch.py sudo systemctl start docker ``` 2) Make container - -- JETSON ```bash -sudo docker compose -f compose/docker-compose.yml up -d dev-jetson +sudo docker compose -f compose/docker-compose.yml up -d dev ``` - -- RUBIK -```bash -sudo docker compose -f compose/docker-compose.yml up -d dev-rubik -``` - 3) Exec into container - -- JETSON ```bash -sudo docker exec -it ros2-dev-jetson bash +docker exec -it ros2-dev bash ``` - -- RUBIK -```bash -sudo docker exec -it ros2-dev-rubik bash -``` - 4) Setup ROS ```bash source /opt/ros/humble/setup.bash colcon build source install/setup.bash -``` - -5) Launch - -- JETSON -```bash -ros2 launch autonomous_kart bringup_jetson.launch.py -``` - -- RUBIK -```bash -ros2 launch autonomous_kart bringup_rubik.launch.py -``` - -- ALL -```bash -ros2 launch autonomous_kart bringup_all.launch.py +ros2 launch autonomous_kart bringup_${TARGET_DEVICE:-jetson}.launch.py ``` \ No newline at end of file From 101c49827f55cd970274b0a5d99cc110a01db134 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Sun, 17 May 2026 17:29:40 +0000 Subject: [PATCH 33/35] now can revert devcontainer json much cleaner --- .devcontainer/devcontainer.jetson.json | 43 ------------------- ...container.rubik.json => devcontainer.json} | 13 +----- 2 files changed, 2 insertions(+), 54 deletions(-) delete mode 100644 .devcontainer/devcontainer.jetson.json rename .devcontainer/{devcontainer.rubik.json => devcontainer.json} (89%) diff --git a/.devcontainer/devcontainer.jetson.json b/.devcontainer/devcontainer.jetson.json deleted file mode 100644 index d1adb667..00000000 --- a/.devcontainer/devcontainer.jetson.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "ROS2 Jetson Dev", - - "dockerComposeFile": [ - "../compose/docker-compose.yml" - ], - - "service": "dev-jetson", - - "workspaceFolder": "/ws", - - "containerEnv": { - "ROS_DOMAIN_ID": "42", - "ROS_LOCALHOST_ONLY": "0", - "RMW_IMPLEMENTATION": "rmw_cyclonedds_cpp", - "CYCLONEDDS_URI": "file:///ws/docker/cyclonedds.xml" - }, - - "customizations": { - "vscode": { - "extensions": [ - "ms-python.python", - "ms-python.vscode-pylance", - "ms-azuretools.vscode-docker", - "foxglove.vscode-foxglove" - ], - - "settings": { - "python.defaultInterpreterPath": "/ws/.venv/bin/python", - - "python.analysis.extraPaths": [ - "/ws/install", - "/opt/ros/humble/lib/python3.10/site-packages", - "/opt/ros/humble/local/lib/python3.10/dist-packages", - "/ws/install/lib/python3.10/site-packages" - ] - } - } - }, - - "postCreateCommand": "bash /ws/scripts/devcontainer_post_create.sh", - "postAttachCommand": "bash /ws/scripts/devcontainer_post_attach.sh" -} \ No newline at end of file diff --git a/.devcontainer/devcontainer.rubik.json b/.devcontainer/devcontainer.json similarity index 89% rename from .devcontainer/devcontainer.rubik.json rename to .devcontainer/devcontainer.json index 0a4e9a09..198b41ad 100644 --- a/.devcontainer/devcontainer.rubik.json +++ b/.devcontainer/devcontainer.json @@ -1,21 +1,15 @@ { - "name": "ROS2 Rubik Dev", - + "name": "ROS2 rclpy Dev", "dockerComposeFile": [ "../compose/docker-compose.yml" ], - - "service": "dev-rubik", - + "service": "dev", "workspaceFolder": "/ws", - "containerEnv": { "ROS_DOMAIN_ID": "42", "ROS_LOCALHOST_ONLY": "0", - "RMW_IMPLEMENTATION": "rmw_cyclonedds_cpp", "CYCLONEDDS_URI": "file:///ws/docker/cyclonedds.xml" }, - "customizations": { "vscode": { "extensions": [ @@ -24,10 +18,8 @@ "ms-azuretools.vscode-docker", "foxglove.vscode-foxglove" ], - "settings": { "python.defaultInterpreterPath": "/ws/.venv/bin/python", - "python.analysis.extraPaths": [ "/ws/install", "/opt/ros/humble/lib/python3.10/site-packages", @@ -37,7 +29,6 @@ } } }, - "postCreateCommand": "bash /ws/scripts/devcontainer_post_create.sh", "postAttachCommand": "bash /ws/scripts/devcontainer_post_attach.sh" } \ No newline at end of file From 37f16a38cde7dea1fb16b7528b3aa1cdec11dee0 Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Wed, 20 May 2026 14:53:31 +0000 Subject: [PATCH 34/35] master node/api on rubik --- .../autonomous_kart/launch/bringup_jetson.launch.py | 5 ----- .../autonomous_kart/launch/bringup_rubik.launch.py | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py index 1bf5d556..4bdd4489 100644 --- a/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py @@ -38,11 +38,6 @@ def generate_launch_description(): name="opencv_pathfinder_node", parameters=[gps_yaml], ), - Node( - package="autonomous_kart", - executable="master_api", - name="master_api", - ), Node( package="autonomous_kart", executable="localization_node", diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py index 69dc500e..07414f51 100644 --- a/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_rubik.launch.py @@ -29,6 +29,11 @@ def generate_launch_description(): name="camera_node", parameters=[camera_yaml], ), + Node( + package="autonomous_kart", + executable="master_api", + name="master_api", + ), ] ), ] From fb824eb73e48c0586f4181574e50b21661c0888f Mon Sep 17 00:00:00 2001 From: LelsersLasers Date: Wed, 20 May 2026 16:38:18 +0000 Subject: [PATCH 35/35] missing e_comms params --- .../autonomous_kart/launch/bringup_jetson.launch.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py b/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py index 4bdd4489..111ee4de 100644 --- a/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py +++ b/src/autonomous_kart/autonomous_kart/launch/bringup_jetson.launch.py @@ -13,9 +13,11 @@ def generate_launch_description(): safety_yaml = os.path.join(pkg_share, "params", "safety.yaml") system_yaml = os.path.join(pkg_share, "params", "system.yaml") pathfinder_yaml = os.path.join(pkg_share, "params", "pathfinder.yaml") - localization_yaml = os.path.join(pkg_share, "params", "localization.yaml") imu_yaml = os.path.join(pkg_share, "params", "imu.yaml") e_comms_yaml = os.path.join(pkg_share, "params", "e_comms.yaml") + actuators_yaml = os.path.join(pkg_share, "params", "actuators.yaml") + localization_yaml = os.path.join(pkg_share, "params", "localization.yaml") + opencv_yaml = os.path.join(pkg_share, "params", "opencv_pathfinder.yaml") sim_mode = LaunchConfiguration("simulation_mode") @@ -32,12 +34,6 @@ def generate_launch_description(): name="pathfinder_node", parameters=[pathfinder_yaml, safety_yaml], ), - Node( - package="autonomous_kart", - executable="opencv_pathfinder_node", - name="opencv_pathfinder_node", - parameters=[gps_yaml], - ), Node( package="autonomous_kart", executable="localization_node", @@ -48,7 +44,7 @@ def generate_launch_description(): package="autonomous_kart", executable="e_comms_node", name="e_comms_node", - parameters=[e_comms_yaml], + parameters=[e_comms_yaml, actuators_yaml, pathfinder_yaml], ), Node( package="autonomous_kart",