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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,7 @@ src/backend/generated/
target/
*.pyc

src/main/deploy/config
src/main/deploy/config

*.db
.coverage
11 changes: 6 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ THRIFT_GEN_DIR = $(GEN_DIR)/thrift
THRIFT_TS_SCHEMA_GEN_DIR = $(THRIFT_GEN_DIR)/ts_schema
PROTO_PY_GEN_DIR = $(PROTO_GEN_DIR)/python

prep-project:
if [ ! -d ".venv" ]; then \
python3 -m venv .venv; \
fi

initialize:
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
make test

test:
PYTHONPATH=src pytest

generate-proto-python:
mkdir -p $(PROTO_PY_GEN_DIR)
Expand Down
15 changes: 0 additions & 15 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -220,20 +220,6 @@ def applyBackend(expectedNumOfPis) {
}
}

def installPythonDependencies() {
project.exec {
commandLine "make", "prep-project"
}
}

tasks.register("installPythonDependencies") {
group = "build"
description = "Install Python dependencies"
doLast {
installPythonDependencies()
}
}

buildDynamically("./config.ini")

tasks.register("applyBackend") {
Expand All @@ -252,7 +238,6 @@ tasks.register("generateConfig") {
}
}

tasks.build.dependsOn(tasks.installPythonDependencies)
tasks.build.dependsOn(tasks.generateConfig)
tasks.build.dependsOn(tasks.generateProto)

Expand Down
7 changes: 0 additions & 7 deletions docs/HowToInitialize.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,6 @@ make --version

# Setting Up Workspace

## Clone the repository

```bash
git clone https://github.com/PinewoodRobotics/command-robot-base.git
cd command-robot-base
```

## Initialize the submodules

```bash
Expand Down
10 changes: 10 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[pytest]
pythonpath = src
testpaths = src/backend/python
addopts =
--cov=backend.python.april
--cov=backend.python.pos_extrapolator
--cov=backend.python.common
--cov-report=term-missing
norecursedirs =
lib/
5 changes: 4 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ zeroconf
thrift
opencv-python
requests
ultralytics
ultralytics

# dev deps
pytest-cov
14 changes: 8 additions & 6 deletions src/backend/deployment/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,12 @@ def _deploy_backend_to_pi(
"-p",
pi.password,
"ssh",
"-o",
"StrictHostKeyChecking=no",
"-p",
str(getattr(pi, "port", 22)),
f"ubuntu@{pi.address}",
f"sudo mkdir -p {remote_target_dir}",
f"mkdir -p {remote_target_dir}",
]

mkdir_proc = subprocess.run(mkdir_cmd)
Expand Down Expand Up @@ -248,10 +250,6 @@ def _deploy_compilable(pi: _RaspberryPi, modules: list[_Module]):
from backend.deployment.compilation.cpp.cpp import CPlusPlus
from backend.deployment.compilation.rust.rust import Rust

if os.path.exists(LOCAL_BINARIES_PATH):
shutil.rmtree(LOCAL_BINARIES_PATH)
os.makedirs(LOCAL_BINARIES_PATH, exist_ok=True)

if SHOULD_REBUILD_BINARIES:
for module in modules:
if not isinstance(module, _CompilableModule):
Expand Down Expand Up @@ -350,7 +348,7 @@ class RustModule(_CompilableModule, _RunnableModule):

def get_run_command(self) -> str:
extra_run_args = self.get_extra_run_args()
return f"{LOCAL_BINARIES_PATH}/{get_self_ldd_version()}/{get_self_architecture()}/{self.runnable_name} {extra_run_args}".strip()
return f"{LOCAL_BINARIES_PATH}/{get_self_ldd_version()}/{get_self_architecture()}/rust/{self.runnable_name}/{self.runnable_name} {extra_run_args}".strip()

@dataclass
class ProtobufModule(_CompilableModule):
Expand Down Expand Up @@ -403,6 +401,10 @@ def with_preset_pi_addresses(
def with_automatic_discovery(
modules: list[_Module], backend_local_path: str = "src/backend/"
):
if os.path.exists(LOCAL_BINARIES_PATH):
shutil.rmtree(LOCAL_BINARIES_PATH)
os.makedirs(LOCAL_BINARIES_PATH, exist_ok=True)

raspberrypis = _RaspberryPi.discover_all()
DeploymentOptions.with_preset_pi_addresses(
raspberrypis, modules, backend_local_path
Expand Down
10 changes: 0 additions & 10 deletions src/backend/python/common/__tests__/test_all.py

This file was deleted.

4 changes: 0 additions & 4 deletions src/backend/python/common/__tests__/test_system.py
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
from backend.python.common.util.system import get_local_hostname


def test_get_local_hostname():
assert get_local_hostname() == "Deniss-MacBook-Pro.local"
6 changes: 0 additions & 6 deletions src/backend/python/common/camera/abstract_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,6 @@ def __init__(
exposure_time: float = -1,
brightness: int | None = None,
) -> None:
if isinstance(camera_port, str):
try:
camera_port: int = int(camera_port)
except ValueError:
pass

self.port: int | str = camera_port
self.camera_name: str = camera_name
self.width: int = width
Expand Down
13 changes: 10 additions & 3 deletions src/backend/python/common/camera/image_utils.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import time
from logging import info
from typing import cast

import cv2
from cv2.typing import MatLike
import numpy as np

from backend.python.common.debug.logger import stats_for_nerds
from backend.generated.proto.python.sensor.camera_sensor_pb2 import (
ImageCompression,
ImageData,
ImageFormat,
)
from backend.python.common.debug.logger import stats_for_nerds


def from_proto_format(format: ImageFormat) -> int:
Expand Down Expand Up @@ -58,10 +60,15 @@ def compress_image(
def decode_image(proto_image: ImageData) -> np.ndarray:
channels = from_proto_format_to_n_channels(proto_image.format)
if proto_image.compression == ImageCompression.JPEG:
return cv2.imdecode(
np.frombuffer(proto_image.image, dtype=np.uint8),
decoded = cv2.imdecode(
cast(MatLike, np.frombuffer(proto_image.image, dtype=np.uint8)),
from_proto_format(proto_image.format),
)
if decoded is None:
raise ValueError(
f"Failed to decode JPEG image (format={proto_image.format}, bytes={len(proto_image.image)})"
)
return cast(np.ndarray, decoded)
else:
return np.frombuffer(proto_image.image, dtype=np.uint8).reshape(
(proto_image.height, proto_image.width, channels)
Expand Down
22 changes: 0 additions & 22 deletions src/backend/python/common/debug/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,28 +87,6 @@ def wrapper(*args, **kwargs):
return decorator


def stats_for_nerds_akit(send_stats: bool = True, print_stats: bool = True):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
if send_stats:
log_to_akit(func.__name__, [(end_time - start_time) * 1000])

if print_stats:
info(
f"Function {func.__name__} took {(end_time - start_time) * 1000}ms to run."
)

return result

return wrapper

return decorator


def init_logging(
prefix: str,
log_level: LogLevel,
Expand Down
4 changes: 0 additions & 4 deletions src/config/april_tags_detection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,10 @@ export const april_tag_detection_config: AprilDetectionConfig = {
send_stats: true,
stats_topic: "apriltag/stats",
pi_name_to_special_detector_config: {
// this section is for special detectors. This means that if you want to use a non-standard detector, say GPU based
// that only works on a specific Pi, you can add it here with the Pi name as the key.
/*
jetson1: {
type: SpecialDetectorType.GPU_CUDA,
py_lib_searchpath:
"/opt/blitz/B.L.I.T.Z/build/release/2.35/aarch64/cpp/cuda-tags-lib/",
},
*/
},
};
35 changes: 35 additions & 0 deletions src/config/cameras/front_left.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
CameraParameters,
CameraType,
} from "generated/thrift/gen-nodejs/camera_types";
import { MatrixUtil, VectorUtil } from "../util/math";

const front_left: CameraParameters = {
pi_to_run_on: "tynan",
name: "front_left",
camera_path: "/dev/usb_cam4",
flags: 0,
width: 800,
height: 600,
max_fps: 100,
camera_matrix: MatrixUtil.buildMatrix([
[685.088010528533, 0.0, 400.456913426101],
[0.0, 685.286311116306, 283.611674040712],
[0.0, 0.0, 1.0],
]),
dist_coeff: VectorUtil.fromArray([
0.0370949377097917, 0.041319913100527, -0.00128168607814328,
-0.00128042296949747, -0.298591139932664,
]),
exposure_time: 10,
camera_type: CameraType.OV2311,
video_options: {
send_feed: true,
compression_quality: 50,
publication_topic: "cameras/front_left",
do_compression: true,
overlay_tags: true,
},
};

export default front_left;
34 changes: 34 additions & 0 deletions src/config/cameras/front_right.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {
CameraParameters,
CameraType,
} from "generated/thrift/gen-nodejs/camera_types";
import { MatrixUtil, VectorUtil } from "../util/math";

const front_right: CameraParameters = {
pi_to_run_on: "tynan",
name: "front_right",
camera_path: "/dev/usb_cam2",
flags: 0,
width: 800,
height: 600,
max_fps: 100,
camera_matrix: MatrixUtil.buildMatrix([
[685.1818937239501, 0.0, 414.2897986078692],
[0.0, 685.3366953090806, 307.27153822775506],
[0.0, 0.0, 1.0],
]),
dist_coeff: VectorUtil.fromArray([
0.03841168751857183, -0.03836398867353221, 0.00011911539228647425,
-0.00047135490659979865, -0.011145047269650642,
]),
exposure_time: 10,
camera_type: CameraType.OV2311,
video_options: {
send_feed: false,
do_compression: true,
overlay_tags: false,
compression_quality: 30,
},
};

export default front_right;
35 changes: 35 additions & 0 deletions src/config/cameras/jetson_cam.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
CameraParameters,
CameraType,
} from "generated/thrift/gen-nodejs/camera_types";
import { MatrixUtil, VectorUtil } from "../util/math";

const jetson_cam: CameraParameters = {
pi_to_run_on: "jetson1",
name: "jetson_cam",
camera_path: "/dev/video0",
flags: 0,
width: 640,
height: 480,
max_fps: 60,
camera_matrix: MatrixUtil.buildMatrix([
[685.088010528533, 0.0, 400.456913426101],
[0.0, 685.286311116306, 283.611674040712],
[0.0, 0.0, 1.0],
]),
dist_coeff: VectorUtil.fromArray([
0.0370949377097917, 0.041319913100527, -0.00128168607814328,
-0.00128042296949747, -0.298591139932664,
]),
exposure_time: 10,
camera_type: 0 as CameraType,
video_options: {
send_feed: true,
publication_topic: "camera/jetson/video",
compression_quality: 90,
do_compression: false,
overlay_tags: false,
},
};

export default jetson_cam;
14 changes: 7 additions & 7 deletions src/config/cameras/logitech_cam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import {
import { MatrixUtil, VectorUtil } from "../util/math";

const logitech_cam: CameraParameters = {
pi_to_run_on: "jetson1",
pi_to_run_on: "nathan-hale",
name: "front_left",
camera_path: "/dev/video0",
camera_path: "/dev/usb_cam2",
flags: 0,
width: 640,
height: 480,
Expand All @@ -21,14 +21,14 @@ const logitech_cam: CameraParameters = {
-0.44180630590282977, 0.23535469092748917, -0.0020750769021071484,
-7.455571357241929e-5, -0.08061071367847858,
]),
exposure_time: 150,
exposure_time: 400,
camera_type: CameraType.ULTRAWIDE_100,
brightness: 200,
brightness: 50,
video_options: {
send_feed: false,
overlay_tags: true,
send_feed: true,
overlay_tags: false,
publication_topic: "camera/logitech/video",
compression_quality: 30,
compression_quality: 90,
do_compression: true,
},
};
Expand Down
Loading