Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Use the public base image so the devcontainer build is intentionally minimal.
# If you later need to add extra layers (tools, caches, deps), add them below.
FROM kestreldev/l4t-ros2-docker:jazzy

# Keep the devcontainer image minimal; runtime apt/source configuration is performed
# by the repository-level installer script `scripts/rosdep_install.sh` so the
# devcontainer image doesn't force package installation at build-time.

# Example of adding small, local dev-only tooling later:
# RUN apt-get update && apt-get install -y --no-install-recommends vim less && rm -rf /var/lib/apt/lists/*
18 changes: 18 additions & 0 deletions .devcontainer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
This devcontainer builds the `l4t-ros2:jazzy` image using the provided `Dockerfile` and starts a container with the same runtime options used by the project's documentation.

Before opening the folder in the devcontainer, allow X connections from the host by running on your host machine:

```
xhost +
```

Then open the repository in VS Code and choose "Reopen in Container". The container is built from `.devcontainer/Dockerfile` and is started with GPU support, host networking, DISPLAY forwarded, and the host's `$HOME` bind-mounted so GUI and ROS tooling work similarly to the manual `docker run` command.

The devcontainer will now run `scripts/rosdep_install.sh` once after the container is created to install ROS package dependencies from the workspace `src/` directory using `rosdep`.

To re-run the installer manually inside the container:

```bash
# from inside the container or via 'devcontainer exec'
bash $HOME/Kestrel/scripts/rosdep_install.sh
```
24 changes: 24 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "Kestrel l4t-ros2:jazzy",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"runArgs": [
"--net=host",
"--runtime=nvidia",
"-e",
"DISPLAY=${localEnv:DISPLAY}",
"-v",
"/tmp/.X11-unix/:/tmp/.X11-unix:rw",
"-v",
"${localEnv:HOME}:${localEnv:HOME}:rw"
],
"containerEnv": {
"DISPLAY": "${localEnv:DISPLAY}"
},
"workspaceFolder": "${localEnv:HOME}/Kestrel",
"postCreateCommand": "bash -lc 'set -euo pipefail; if [ -f \"${containerWorkspaceFolder}/scripts/rosdep_install.sh\" ]; then echo \"Running scripts/rosdep_install.sh\"; bash \"${containerWorkspaceFolder}/scripts/rosdep_install.sh\"; else echo \"No scripts/rosdep_install.sh found; skipping rosdep install.\"; fi'",
"postStartCommand": "echo \"If GUI apps fail to open, run 'xhost +' on the host to allow X connections.\"",
"remoteUser": "jetson"
}
43 changes: 43 additions & 0 deletions .github/workflows/base_image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Process for building and pushing the full Jetson Orin Nano docker image

name: Docker Build Base image

on:
workflow_dispatch:

jobs:
build-base:
name: Build Base Image
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
submodules: 'recursive'

- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: arm64,amd64

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and Push Base Image
uses: docker/build-push-action@v5
with:
context: ./docker/l4t-ros2-docker/jazzy
file: ./docker/l4t-ros2-docker/jazzy/Dockerfile
push: true
platforms: linux/arm64
tags: kestreldev/l4t-ros2-docker:jazzy
cache-from: |
type=registry,ref=kestreldev/l4t-ros2-docker:cache-jazzy
cache-to: |
type=registry,ref=kestreldev/l4t-ros2-docker:cache-jazzy,mode=max
5 changes: 1 addition & 4 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
name: docker-build-and-push

on:
push:
branches:
- main
- pathing_and_workflows
workflow_dispatch:

jobs:
docker-build-and-push:
Expand Down
12 changes: 3 additions & 9 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
[submodule "src/libraries/mavlink"]
path = src/libraries/mavlink
url = https://github.com/mavlink/mavlink
[submodule "src/libraries/mavros"]
path = src/libraries/mavros
url = https://github.com/mavlink/mavros
[submodule "src/driver/vl53l1x"]
path = src/driver/vl53l1x
url = https://github.com/Autonomous-droneProject/ROS2-VL53L1X.git
Expand All @@ -19,6 +13,6 @@
[submodule "docs/KestrelAssembly"]
path = docs/KestrelAssembly
url = https://github.com/Autonomous-droneProject/KestrelAssembly.git
[submodule "src/libraries/geographiclib"]
path = src/libraries/geographiclib
url = https://github.com/geographiclib/geographiclib.git
[submodule "docker/l4t-ros2-docker"]
path = docker/l4t-ros2-docker
url = https://github.com/atinfinity/l4t-ros2-docker.git
1 change: 1 addition & 0 deletions docker/l4t-ros2-docker
Submodule l4t-ros2-docker added at e8534a
File renamed without changes.
Empty file removed docker/ros_entrypoint.sh
Empty file.
139 changes: 139 additions & 0 deletions scripts/rosdep_install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#!/usr/bin/env bash
set -euo pipefail

# Simplified, robust rosdep install script
# Implements the requested sequence:
# 1) install software-properties-common and enable 'universe'
# 2) install curl
# 3) download and install ros2-apt-source .deb from latest GitHub release
# 4) ensure only 'ros2.sources' remains under /etc/apt/sources.list.d/
# 5) run rosdep install --from-paths src --ignore-src -r -y

WORKSPACE_ROOT="$(pwd)"
SRC_DIR="$WORKSPACE_ROOT/src"

echo "[rosdep_install] workspace root: $WORKSPACE_ROOT"

command_exists() { command -v "$1" >/dev/null 2>&1; }

require_sudo() {
if ! command_exists sudo; then
echo "[rosdep_install] ERROR: sudo is required to run this script." >&2
exit 1
fi
}

backup_file() {
local f="$1"
if [ -e "$f" ]; then
sudo cp -a "$f" "${f}.bak-rosdep" || true
echo "[rosdep_install] Backed up $f -> ${f}.bak-rosdep"
fi
}

echo "[rosdep_install] Ensuring apt helpers and universe repository are available..."
require_sudo
sudo env DEBIAN_FRONTEND=noninteractive apt-get update -qq
sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends software-properties-common || true
sudo add-apt-repository -y universe || true

echo "[rosdep_install] Updating apt and installing curl..."
sudo env DEBIAN_FRONTEND=noninteractive apt-get update -qq
sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends curl ca-certificates gnupg lsb-release dpkg || true

# determine latest ros-apt-source release tag
echo "[rosdep_install] Determining latest ros-apt-source release from GitHub..."
ROS_APT_SOURCE_VERSION=$(curl -s https://api.github.com/repos/ros-infrastructure/ros-apt-source/releases/latest | grep -F '"tag_name"' | awk -F'"' '{print $4}' || true)
if [ -z "${ROS_APT_SOURCE_VERSION:-}" ]; then
echo "[rosdep_install] ERROR: could not determine ros-apt-source release tag from GitHub." >&2
echo "[rosdep_install] Aborting. You can add the ROS apt source manually or retry later." >&2
exit 1
fi

# compute UBUNTU codename
CODENAME=$(. /etc/os-release && echo "${UBUNTU_CODENAME:-${VERSION_CODENAME}}")
if [ -z "${CODENAME:-}" ]; then
# fallback to lsb_release
if command_exists lsb_release; then
CODENAME=$(lsb_release -cs)
else
echo "[rosdep_install] ERROR: cannot determine Ubuntu codename." >&2
exit 1
fi
fi

DEBNAME="ros2-apt-source_${ROS_APT_SOURCE_VERSION}.${CODENAME}_all.deb"
TMP_DEB="/tmp/ros2-apt-source.deb"
DOWNLOAD_URL="https://github.com/ros-infrastructure/ros-apt-source/releases/download/${ROS_APT_SOURCE_VERSION}/${DEBNAME}"

echo "[rosdep_install] Downloading ros-apt-source package: $DOWNLOAD_URL"
if ! curl -L -o "$TMP_DEB" "$DOWNLOAD_URL" --fail -s; then
echo "[rosdep_install] ERROR: failed to download $DOWNLOAD_URL" >&2
exit 1
fi

echo "[rosdep_install] Installing $TMP_DEB"
if ! sudo dpkg -i "$TMP_DEB"; then
echo "[rosdep_install] dpkg reported problems, attempting to fix with apt-get -f install..."
sudo env DEBIAN_FRONTEND=noninteractive apt-get -y -f install
sudo dpkg -i "$TMP_DEB" || {
echo "[rosdep_install] ERROR: dpkg installation failed after fixing dependencies." >&2
rm -f "$TMP_DEB" || true
exit 1
}
fi
rm -f "$TMP_DEB"

echo "[rosdep_install] Ensuring only 'ros2.sources' remains under /etc/apt/sources.list.d/"
require_sudo
shopt -s nullglob
ROSDIR=/etc/apt/sources.list.d
for f in "$ROSDIR"/ros2*; do
[ -e "$f" ] || continue
bn=$(basename "$f")
if [ "$bn" != "ros2.sources" ]; then
backup_file "$f"
echo "[rosdep_install] Removing $f"
sudo rm -f "$f" || true
else
echo "[rosdep_install] Keeping $f"
fi
done
shopt -u nullglob

echo "[rosdep_install] Refreshing apt lists..."
sudo env DEBIAN_FRONTEND=noninteractive apt-get update -qq

# Ensure rosdep is installed
if ! command_exists rosdep; then
echo "[rosdep_install] rosdep not found. Installing python3-rosdep via apt..."
sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends python3-rosdep || true
if ! command_exists rosdep; then
echo "[rosdep_install] Attempting pip3 install for rosdep..."
if command_exists pip3; then
pip3 install --user rosdep
export PATH="$HOME/.local/bin:$PATH"
else
echo "[rosdep_install] ERROR: pip3 not found; please install rosdep manually." >&2
exit 1
fi
fi
fi

# Initialize rosdep if needed
if [ ! -f /etc/ros/rosdep/sources.list.d/20-default.list ]; then
echo "[rosdep_install] Initializing rosdep database (sudo may be required)..."
sudo rosdep init || true
fi

echo "[rosdep_install] Updating rosdep database..."
rosdep update || echo "[rosdep_install] rosdep update failed or already up-to-date"

if [ -d "$SRC_DIR" ]; then
echo "[rosdep_install] Running: rosdep install --from-paths $SRC_DIR --ignore-src -r -y"
rosdep install --from-paths "$SRC_DIR" --ignore-src -r -y
else
echo "[rosdep_install] No src directory at $SRC_DIR; skipping rosdep install." >&2
fi

echo "[rosdep_install] Done."
3 changes: 1 addition & 2 deletions src/kestrel_communication/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ find_package(std_msgs REQUIRED)
find_package(kestrel_msgs REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(rclpy REQUIRED)

set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};/usr/share/cmake/mavros_msgs")
find_package(mavros_msgs REQUIRED)

# Include directory for headers
include_directories(include)

Expand Down
13 changes: 2 additions & 11 deletions src/kestrel_control/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
cmake_minimum_required(VERSION 3.10)
project(kestrel_control)

#
#set(CMAKE_PREFIX_PATH "/opt/ros/${ROS_DISTRO}:${CMAKE_PREFIX_PATH}")

# Core build dependencies
find_package(ament_cmake REQUIRED)
find_package(ament_cmake_gtest REQUIRED)
Expand All @@ -12,16 +9,10 @@ find_package(rclpy REQUIRED)
find_package(std_msgs REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(kestrel_msgs REQUIRED)

set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};/usr/share/cmake/geographiclib")
find_package(GeographicLib REQUIRED)

set(control_toolbox_DIR "${ROS_PREFIX}/share/control_toolbox/cmake")
find_package(control_toolbox REQUIRED)


set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};/usr/share/cmake/mavros_msgs")
find_package(mavros_msgs REQUIRED)
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};/usr/share/cmake/geographiclib")
find_package(GeographicLib REQUIRED)

# Include directory for headers
include_directories(include)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include "rclcpp/rclcpp.hpp"
#include "sensor_msgs/msg/nav_sat_fix.hpp"
#include "geometry_msgs/msg/pose_stamped.hpp"
#include "GeographicLib/LocalCartesian.hpp"
#include <GeographicLib/LocalCartesian.hpp>
#include <memory>

namespace kestrel_control
Expand Down
2 changes: 1 addition & 1 deletion src/kestrel_control/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<depend>sensor_msgs</depend>
<depend>geometry_msgs</depend>
<depend>kestrel_msgs</depend>
<depend>GeographicLib</depend>
<depend>libgeographiclib-dev</depend>
<depend>control_toolbox</depend>
<depend>mavros_msgs</depend>
<test_depend>ament_cmake_gtest</test_depend>
Expand Down
2 changes: 1 addition & 1 deletion src/kestrel_description/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<exec_depend>robot_state_publisher</exec_depend>
<exec_depend>rviz2</exec_depend>
<exec_depend>joint_state_publisher_gui</exec_depend>
<exec_depend>gazebo_ros</exec_depend>
<exec_depend>ros-jazzy-gazebo-ros</exec_depend>

<export>
<architecture_independent/>
Expand Down
1 change: 0 additions & 1 deletion src/libraries/geographiclib
Submodule geographiclib deleted from 0a6067
1 change: 0 additions & 1 deletion src/libraries/mavlink
Submodule mavlink deleted from b27d03
1 change: 0 additions & 1 deletion src/libraries/mavros
Submodule mavros deleted from e7a3e4