Skip to content

Commit

Permalink
Blackened
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMariday committed Feb 22, 2024
1 parent 6a2f150 commit dd1b585
Show file tree
Hide file tree
Showing 14 changed files with 168 additions and 59 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install flake8
pip install flake8-bugbear
pip install black
- name: Flake 8 Syntax Errors
run: |
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
- name: Flake 8 Syntax Warnings
run: |
flake8 . --count --statistics
flake8 . --count --statistics
- name: Black formatting
run: |
black . --check
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![Windows](https://github.com/TheMariday/L3D/actions/workflows/test_windows.yml/badge.svg)](https://github.com/TheMariday/L3D/actions/workflows/test_windows.yml)
[![Ubuntu](https://github.com/TheMariday/L3D/actions/workflows/test_ubuntu.yml/badge.svg)](https://github.com/TheMariday/L3D/actions/workflows/test_ubuntu.yml)
[![MacOS](https://github.com/TheMariday/L3D/actions/workflows/test_mac.yml/badge.svg)](https://github.com/TheMariday/L3D/actions/workflows/test_mac.yml)
[![Style](https://github.com/TheMariday/L3D/actions/workflows/lint.yml/badge.svg)](https://github.com/TheMariday/L3D/actions/workflows/lint.yml)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)


This is a selection of tools to map LEDs into 2D and 3D space using only your webcam!
Expand Down Expand Up @@ -96,4 +96,4 @@ I would really love to hear what you think and if you have any bugs or improveme

If you implement a backend that you think others might use, please raise a pull request or just drop me a message on Telegram!

Please install and run flake8 before submitting changes thank you!
If you want a super speed PR, run flake8, flake8-bugbear and black before submitting changes!
5 changes: 4 additions & 1 deletion backends/custom/custom_backend.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# import some_led_library


class Backend:

def __init__(self, led_count: int):
# Remove the following line after you have implemented the set_led function!
raise NotImplementedError("Could not load backend as it has not been implemented, go implement it!")
raise NotImplementedError(
"Could not load backend as it has not been implemented, go implement it!"
)

def set_led(self, led_index: int, on: bool):
# Write your code for controlling your LEDs here
Expand Down
2 changes: 2 additions & 0 deletions backends/fadecandy/opc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env python
# fmt: off

"""Python Client library for Open Pixel Control
http://github.com/zestyping/openpixelcontrol
Expand Down Expand Up @@ -211,3 +212,4 @@ def set_interpolation(self, enabled = True):
return True


# fmt: on
6 changes: 3 additions & 3 deletions backends/lcm/lcm_backend.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@


class Backend:

def __init__(self, led_count):
raise NotImplementedError("Could not load backend as it has not been implemented, go implement it!")
raise NotImplementedError(
"Could not load backend as it has not been implemented, go implement it!"
)

def set_led(self, led_index: int, on: bool):
pass
15 changes: 11 additions & 4 deletions backends/test_backend.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import argparse
import sys
sys.path.append('./')

sys.path.append("./")
from lib import utils
from lib.color_print import cprint
import time

if __name__ == "__main__":

parser = argparse.ArgumentParser(description='Tests a particular backend by making a reference led blink')
parser = argparse.ArgumentParser(
description="Tests a particular backend by making a reference led blink"
)

utils.add_backend_args(parser)

parser.add_argument("--reference_led", type=int,
help="This is the index of the LED should be visible from the camera", default=0)
parser.add_argument(
"--reference_led",
type=int,
help="This is the index of the LED should be visible from the camera",
default=0,
)

args = parser.parse_args()

Expand Down
21 changes: 16 additions & 5 deletions backends/wled/wled_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,31 @@ def get_led_count(self):

# Get the LED Count straight from the WLED Device :D
if response.status_code != 200:
raise ConnectionError(f"Failed to retrieve LED count. Status code: {response.status_code}")
raise ConnectionError(
f"Failed to retrieve LED count. Status code: {response.status_code}"
)

info_data = response.json()
return info_data['leds']['count']
return info_data["leds"]["count"]

def reset_wled(self):

# Set all the LED's to black on launch
payload = {"seg": [{"start": 0, "stop": self.get_led_count(), "sel": True}, {"stop": 0}]}
payload = {
"seg": [
{"start": 0, "stop": self.get_led_count(), "sel": True},
{"stop": 0},
]
}

# Send the HTTP POST request to WLED API
response = requests.post(self.state_endpoint, json=payload)

# Check if the request was successful (HTTP status code 200)
if response.status_code != 200:
raise ConnectionError(f"Failed to retrieve LED count. Status code: {response.status_code}")
raise ConnectionError(
f"Failed to retrieve LED count. Status code: {response.status_code}"
)
[self.set_led(i, False) for i in range(self.get_led_count())]

def set_led(self, led_index: int, on: bool):
Expand All @@ -42,4 +51,6 @@ def set_led(self, led_index: int, on: bool):

# Check if the request was successful (HTTP status code 200)
if response.status_code != 200:
raise ConnectionError(f"WLED Backend failed to set LED state. Status code: {response.status_code}")
raise ConnectionError(
f"WLED Backend failed to set LED state. Status code: {response.status_code}"
)
2 changes: 1 addition & 1 deletion lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def get_backend(backend_name, led_count, server=""):
from backends.lcm import lcm_backend
return lcm_backend.Backend(led_count)

raise "Invalid backend name"
raise RuntimeError("Invalid backend name")

except NotImplementedError:
cprint(f"Failed to initialise backend {backend_name}, you need to implement it or use the "
Expand Down
21 changes: 16 additions & 5 deletions scripts/camera_check.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
import argparse
import sys
sys.path.append('./')

sys.path.append("./")
from lib.utils import add_camera_args
from lib import L3D
from lib.color_print import cprint, Col

if __name__ == "__main__":

parser = argparse.ArgumentParser(description='Tests your webcam and LED detection algorithms')
parser = argparse.ArgumentParser(
description="Tests your webcam and LED detection algorithms"
)

add_camera_args(parser)

args = parser.parse_args()

if args.width * args.height < 0:
cprint("Failed to start camera checker as both camera width and height need to be provided", format=Col.FAIL)
cprint(
"Failed to start camera checker as both camera width and height need to be provided",
format=Col.FAIL,
)
quit()

l3d = L3D.L3D(args.device, args.exposure, args.threshold, width=args.width, height=args.height)
l3d = L3D.L3D(
args.device, args.exposure, args.threshold, width=args.width, height=args.height
)

cprint("Camera connected! Hold an LED up to the camera to check LED identification", format=Col.BLUE)
cprint(
"Camera connected! Hold an LED up to the camera to check LED identification",
format=Col.BLUE,
)

l3d.show_debug()
49 changes: 35 additions & 14 deletions scripts/capture_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,44 @@

import cv2
from tqdm import tqdm
sys.path.append('./')

sys.path.append("./")
from lib import utils
from lib import L3D
from lib.color_print import cprint, Col

if __name__ == "__main__":

parser = argparse.ArgumentParser(description='Captures LED flashes to file')
parser = argparse.ArgumentParser(description="Captures LED flashes to file")

utils.add_camera_args(parser)
utils.add_backend_args(parser)

parser.add_argument("--output_dir", type=str, help="The output folder for your capture", required=True)
parser.add_argument(
"--output_dir",
type=str,
help="The output folder for your capture",
required=True,
)

parser.add_argument("--led_count", type=int,
help="How many LEDs are in your system", required=True)
parser.add_argument(
"--led_count", type=int, help="How many LEDs are in your system", required=True
)

parser.add_argument("--latency", type=int,
help="The expected latency in ms from an LED being updated to that being updated in the camera",
default=1000)
parser.add_argument(
"--latency",
type=int,
help="The expected latency in ms from an LED being updated to that being updated in the camera",
default=1000,
)

args = parser.parse_args()

led_backend = utils.get_backend(args.backend, args.led_count, args.server)

l3d = L3D.L3D(args.device, args.exposure, args.threshold, width=args.width, height=args.height)
l3d = L3D.L3D(
args.device, args.exposure, args.threshold, width=args.width, height=args.height
)

output_dir_full = os.path.join(os.getcwd(), "my_scans", args.output_dir)

Expand All @@ -40,16 +52,23 @@

# The filename is made out of the date, then the resolution of the camera
string_time = time.strftime("%Y%m%d-%H%M%S")
filename = f"capture_{string_time}_{l3d.cam.get_width()}_{l3d.cam.get_height()}.csv"
filename = (
f"capture_{string_time}_{l3d.cam.get_width()}_{l3d.cam.get_height()}.csv"
)

filepath = os.path.join(output_dir_full, filename)
cprint(f"Opening scan file {filepath}\n")
with open(filepath, 'a') as output_file:
with open(filepath, "a") as output_file:

total_leds_found = 0

for led_id in tqdm(range(args.led_count), unit="LEDs", desc=f"Capturing sequence to {filename}",
total=args.led_count, smoothing=0):
for led_id in tqdm(
range(args.led_count),
unit="LEDs",
desc=f"Capturing sequence to {filename}",
total=args.led_count,
smoothing=0,
):

led_backend.set_led(led_id, True)

Expand All @@ -60,7 +79,9 @@
result = l3d.find_led(True)

if result: # Then no led is found! next
output_file.write(f"{led_id},{result.center[0]},{result.center[1]}\n")
output_file.write(
f"{led_id},{result.center[0]},{result.center[1]}\n"
)
total_leds_found += 1

led_backend.set_led(led_id, False)
Expand Down
35 changes: 26 additions & 9 deletions scripts/latency_check.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import argparse
import math
import sys
sys.path.append('./')

sys.path.append("./")
from lib import utils
from lib import L3D
from lib.color_print import cprint, Col
Expand All @@ -11,10 +12,16 @@

if __name__ == "__main__":

parser = argparse.ArgumentParser(description='Tests the functionality and latency of your LED backend')
parser = argparse.ArgumentParser(
description="Tests the functionality and latency of your LED backend"
)

parser.add_argument("--reference_led", type=int,
help="This is the index of the LED should be visible from the camera", default=0)
parser.add_argument(
"--reference_led",
type=int,
help="This is the index of the LED should be visible from the camera",
default=0,
)

utils.add_camera_args(parser)
utils.add_backend_args(parser)
Expand All @@ -29,20 +36,27 @@

led_backend.set_led(args.reference_led, False)

l3d = L3D.L3D(args.device, args.exposure, args.threshold, width=args.width, height=args.height)
l3d = L3D.L3D(
args.device, args.exposure, args.threshold, width=args.width, height=args.height
)

# wait for 1 seconds for the backend to update, we don't know the latency at this point
time.sleep(1)

result = l3d.find_led()
if result is not None:
cprint(f"All LEDs should be off, however LED has been detected at {result.center},"
f" please run camera_check to ensure the detector is working properly", Col.FAIL)
cprint(
f"All LEDs should be off, however LED has been detected at {result.center},"
f" please run camera_check to ensure the detector is working properly",
Col.FAIL,
)
quit()

latencies = []

for _ in tqdm(range(100), unit="Tests", desc="Testing average latency", total=100, smoothing=0):
for _ in tqdm(
range(100), unit="Tests", desc="Testing average latency", total=100, smoothing=0
):
# Set reference led to off and spin until L3D can't find the led anymore
led_backend.set_led(args.reference_led, False)
while l3d.find_led() is not None:
Expand Down Expand Up @@ -72,4 +86,7 @@

suggested_latency = round((np.percentile(latencies, 99) * 1.1) * 1000)

cprint(f"Suggested latency value for 99% of cases + 10%: {suggested_latency}ms", Col.BLUE)
cprint(
f"Suggested latency value for 99% of cases + 10%: {suggested_latency}ms",
Col.BLUE,
)
Loading

0 comments on commit dd1b585

Please sign in to comment.