import "../../support/just/plan.just"
ROOT := shell('cd "$1/../.." && pwd', justfile_directory())
# Run the Bevy + Copper simulation loop.
default: sim
# Compile both independent multi-Copper subsystem targets.
subsystems-check: end2end-check
# Validate every feature-selected MCU, compute, and deployment graph.
config-matrix:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo test -p cu-flight-controller --no-default-features --features logreader --test config_matrix
# Compile the ZED-enabled compute graph and the independent MCU firmware graph.
end2end-check:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo check -p cu-flight-controller --no-default-features --features end2end --bin quad-compute
cargo check --config examples/cu_flight_controller/.cargo/config-firmware.toml --no-default-features --features firmware -p cu-flight-controller --bin quad
# Run the onboard-compute graph with the ZED camera source enabled.
end2end:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo run -p cu-flight-controller --no-default-features --features end2end --bin quad-compute
# Render the simulated default mission across the complete two-subsystem deployment.
dag config="flight_controller.ron" mission="default" features="sim":
#!/usr/bin/env bash
set -euo pipefail
invocation_dir="{{invocation_directory()}}"
cfg_path="${invocation_dir}/{{config}}"
if [[ ! -f "$cfg_path" ]]; then
echo "No Copper config found at ${cfg_path}" >&2
exit 1
fi
cd "{{ROOT}}"
mission_value="{{mission}}"
features_value="{{features}}"
args=()
if [[ -n "$mission_value" ]]; then
args+=(--mission "$mission_value")
fi
if [[ -n "$features_value" ]]; then
args+=(--features "$features_value")
fi
cargo run -p cu29-runtime --bin cu29-rendercfg -- "${args[@]}" --open "$cfg_path"
# A quick test to see if the sim can pick up your RC.
rc:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo run -p cu-flight-controller --no-default-features --features sim --bin rc-tester
# Run the Bevy + Copper simulation loop.
sim:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo --config examples/cu_flight_controller/.cargo/config.toml run -r -p cu-flight-controller --no-default-features --features sim,forest-world --bin quad-sim
# Run a self-starting autonomous demo and exit cleanly so logs are finalized.
demo:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo --config examples/cu_flight_controller/.cargo/config.toml run -r -p cu-flight-controller --no-default-features --features sim,forest-world,autonomous-demo --bin quad-sim
# Run the Bevy + Copper simulation loop in the urban world.
sim-urban:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo --config examples/cu_flight_controller/.cargo/config.toml run -r -p cu-flight-controller --no-default-features --features sim,urban-world --bin quad-sim
# Run the simulator with ViTFly inference on NVIDIA CUDA.
sim-cuda:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo run --release -p cu-flight-controller --no-default-features --features vitfly-cuda,forest-world --bin quad-sim
# Run the replay-backed remote debug server for the flight controller log.
resim-mcu-debug debug_base="copper/examples/cu_flight_controller/debug/v1" log="logs/flight_controller_sim.copper" replay_log="logs/flight_controller_resim.copper":
#!/usr/bin/env bash
set -euo pipefail
example_dir="{{justfile_directory()}}"
log="{{log}}"
replay_log="{{replay_log}}"
if [[ "$log" != /* ]]; then
log="${example_dir}/${log}"
fi
if [[ "$replay_log" != /* ]]; then
replay_log="${example_dir}/${replay_log}"
fi
cd "{{ROOT}}"
cargo --config examples/cu_flight_controller/.cargo/config.toml run --profile debug-optimized -p cu-flight-controller --no-default-features --features sim-debug --bin quad-resim -- \
--debug-base "{{debug_base}}" \
--log-base "$log" \
--replay-log-base "$replay_log"
# Run the replay-backed debugger for the compute log, including the depth
# images that were actually presented to ViTFly.
resim-compute-debug debug_base="copper/examples/cu_flight_controller/compute/debug/v1" log="logs/flight_compute_sim.copper" replay_log="logs/flight_compute_resim.copper":
#!/usr/bin/env bash
set -euo pipefail
example_dir="{{justfile_directory()}}"
log="{{log}}"
replay_log="{{replay_log}}"
if [[ "$log" != /* ]]; then
log="${example_dir}/${log}"
fi
if [[ "$replay_log" != /* ]]; then
replay_log="${example_dir}/${replay_log}"
fi
cd "{{ROOT}}"
cargo --config examples/cu_flight_controller/.cargo/config.toml run --profile debug-optimized -p cu-flight-controller --no-default-features --features sim-debug --bin quad-compute-resim -- \
--debug-base "{{debug_base}}" \
--log-base "$log" \
--replay-log-base "$replay_log"
# Run the Bevy + Copper simulation loop with cu_bevymon embedded in the window.
bevy:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo run -p cu-flight-controller --no-default-features --features bevymon,forest-world --bin quad-bevymon
# Rebuild the local prototype-world GLB, editable Blender scene, and spawn-point preview.
forest-assets:
#!/usr/bin/env bash
set -euo pipefail
cd "{{invocation_directory()}}"
blender --background --python tools/build_forest.py
# Download the local scene assets needed by the browser BevyMon app.
prepare-assets:
#!/usr/bin/env bash
set -euo pipefail
cd "{{invocation_directory()}}"
mkdir -p assets
if [[ ! -f "assets/quadcopter.glb" ]]; then
echo "Downloading quadcopter.glb..."
curl --fail --location --silent --show-error --output "assets/quadcopter.glb" "https://cdn.copper-robotics.com/quadcopter.glb"
fi
if [[ ! -f "assets/forest.glb" ]]; then
echo "Downloading forest.glb..."
curl --fail --location --silent --show-error --output "assets/forest.glb" "https://cdn.copper-robotics.com/forest.glb"
fi
if [[ ! -f "assets/skybox.ktx2" ]]; then
echo "Downloading skybox.ktx2..."
curl --fail --location --silent --show-error --output "assets/skybox.ktx2" "https://cdn.copper-robotics.com/skybox.ktx2"
fi
if [[ ! -f "assets/specular_map.ktx2" ]]; then
echo "Downloading specular_map.ktx2..."
curl --fail --location --silent --show-error --output "assets/specular_map.ktx2" "https://cdn.copper-robotics.com/specular_map.ktx2"
fi
# Serve the BevyMon flight controller sim in the browser.
web:
#!/usr/bin/env bash
set -euo pipefail
if ! command -v trunk >/dev/null 2>&1; then
echo "Missing trunk. Install with: cargo install --locked trunk" >&2
exit 1
fi
cd "{{invocation_directory()}}"
just prepare-assets
trunk serve --open
# Build a static browser bundle into dist/flight-controller with hashed asset filenames.
web-dist:
#!/usr/bin/env bash
set -euo pipefail
if ! command -v trunk >/dev/null 2>&1; then
echo "Missing trunk. Install with: cargo install --locked trunk" >&2
exit 1
fi
cd "{{invocation_directory()}}"
just prepare-assets
rm -rf dist/flight-controller
trunk build --release --public-url ./ --dist dist/flight-controller
echo "Static web bundle written to ${PWD}/dist/flight-controller"
# Extract CopperLists from a log file (JSON export).
logreader log="logs/flight_controller_sim.copper":
#!/usr/bin/env bash
set -euo pipefail
example_dir="{{justfile_directory()}}"
log="{{log}}"
if [[ "$log" != /* ]]; then
log="${example_dir}/${log}"
fi
cd "{{ROOT}}"
RUST_BACKTRACE=1 cargo run -p cu-flight-controller --no-default-features --features logreader --bin quad-logreader -- "$log" extract-copperlists --export-format json
# Extract compute CopperLists, including ViTFly predictions (JSON export).
compute-logreader log="logs/flight_compute_sim.copper":
#!/usr/bin/env bash
set -euo pipefail
log="{{log}}"
if [[ "$log" != /* ]]; then
log="{{justfile_directory()}}/${log}"
fi
cd "{{ROOT}}"
RUST_BACKTRACE=1 cargo run -p cu-flight-controller --no-default-features --features compute-logreader --bin quad-compute-logreader -- "$log" extract-copperlists --export-format json
# Run the compute-subsystem log reader fsck.
compute-fsck log="logs/flight_compute_sim.copper":
#!/usr/bin/env bash
set -euo pipefail
log="{{log}}"
if [[ "$log" != /* ]]; then
log="{{justfile_directory()}}/${log}"
fi
cd "{{ROOT}}"
RUST_BACKTRACE=1 cargo run -p cu-flight-controller --no-default-features --features compute-logreader --bin quad-compute-logreader -- "$log" fsck
# Build the cu_flight_controller Python extension module.
py-build:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo rustc -p cu-flight-controller --no-default-features --features python-bindings --lib --crate-type cdylib
# Python example reading the log.
py log="logs/flight_controller_sim.copper": py-build
#!/usr/bin/env bash
set -euo pipefail
example_dir="{{justfile_directory()}}"
log="{{log}}"
if [[ "$log" != /* ]]; then
log="${example_dir}/${log}"
fi
cd "{{ROOT}}"
cargo rustc -p cu-flight-controller --no-default-features --features python-bindings --lib --crate-type cdylib
python3 "${example_dir}/python/print_gnss_from_log.py" "$log"
# Print GNSS coordinates from a Copper log via the Python extension.
py-gnss log="logs/flight_controller_sim.copper":
#!/usr/bin/env bash
set -euo pipefail
example_dir="{{justfile_directory()}}"
log="{{log}}"
if [[ "$log" != /* ]]; then
log="${example_dir}/${log}"
fi
cd "{{ROOT}}"
cargo rustc -p cu-flight-controller --no-default-features --features python-bindings --lib --crate-type cdylib
python3 "${example_dir}/python/print_gnss_from_log.py" "$log"
# Run log reader fsck against a log file.
fsck log="logs/flight_controller_sim.copper":
#!/usr/bin/env bash
set -euo pipefail
example_dir="{{justfile_directory()}}"
log="{{log}}"
if [[ "$log" != /* ]]; then
log="${example_dir}/${log}"
fi
cd "{{ROOT}}"
RUST_BACKTRACE=1 cargo run -p cu-flight-controller --no-default-features --features logreader --bin quad-logreader -- "$log" fsck
# Extract text logs with a specified log index directory.
textlogs log="logs/embedded.copper" index="../../target/debug/cu29_log_index":
#!/usr/bin/env bash
set -euo pipefail
example_dir="{{justfile_directory()}}"
log="{{log}}"
index="{{index}}"
if [[ "$log" != /* ]]; then
log="${example_dir}/${log}"
fi
if [[ "$index" != /* ]]; then
index="${example_dir}/${index}"
fi
[[ -e "$index" ]] || { echo "log index not found: $index" >&2; exit 1; }
cd "{{ROOT}}"
RUST_BACKTRACE=1 cargo run -p cu-flight-controller --no-default-features --features logreader --bin quad-logreader -- "$log" extract-text-log "$index"
# Build and run firmware with textlogs enabled (release profile).
fw:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo run --release --config examples/cu_flight_controller/.cargo/config-firmware.toml --no-default-features --features firmware,textlogs -p cu-flight-controller --bin quad
# Release release. With no textlogs.
fwr:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo run --profile screaming --config examples/cu_flight_controller/.cargo/config-firmware.toml --no-default-features --features firmware -p cu-flight-controller --bin quad
# Debug (it won't be fast enough to run be at least you van debug the bringup).
fwd:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
cargo run --config examples/cu_flight_controller/.cargo/config-firmware.toml --no-default-features --features firmware,log-level-debug -p cu-flight-controller --bin quad
# Attach to the already-flashed target without rebuilding or flashing.
attach:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ROOT}}"
probe-rs attach --chip STM32H743VITx --protocol swd target/thumbv7em-none-eabihf/release/quad