Skip to content

Commit

Permalink
Format with black and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
CrispyBacon1999 committed Dec 17, 2019
1 parent 300937f commit a1fed9d
Show file tree
Hide file tree
Showing 12 changed files with 155 additions and 36 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
__pipcache__
docs/_build
**/__pycache__
docs/_build
bin
38 changes: 38 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
language: python
sudo: required

python:
- "3.7"
- "3.6"
- "3.5"

matrix:
fast_finish: true

jobs:
include:
- stage: format-check
python:
- "3.6"
install:
- pip install black
script:
- black --check --diff .

- stage: deploy
if: tag IS present
python: "3.6"
install: skip
script: skip
deploy:
- provider: pypi
user: $PYPI_USERNAME
password: $PYPI_PASSWORD
distributions: sdist bdist_wheel
on:
tags: true

install:
- "pip install -r requirements.txt"
script:
- pytest
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) [year] [fullname]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
21 changes: 9 additions & 12 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
#
import os
import sys
sys.path.insert(0, os.path.abspath('../src'))

sys.path.insert(0, os.path.abspath("../src"))

on_rtd = os.environ.get("READTHEDOCS", None) == "True"

Expand All @@ -23,9 +24,9 @@

# -- Project information -----------------------------------------------------

project = 'RobotPy Limelight'
copyright = '2019, Josh Bacon'
author = 'Josh Bacon'
project = "RobotPy Limelight"
copyright = "2019, Josh Bacon"
author = "Josh Bacon"
version = "2020"
release = version

Expand All @@ -34,21 +35,17 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.napoleon"
]
extensions = ["sphinx.ext.autodoc", "sphinx.ext.autosummary", "sphinx.ext.napoleon"]

master_doc = "index"

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]


# -- Options for HTML output -------------------------------------------------
Expand All @@ -65,4 +62,4 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]
Empty file added limelight/__init__.py
Empty file.
46 changes: 28 additions & 18 deletions src/limelight.py → limelight/limelight.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,30 @@
import typing
from typing import Tuple


class LEDState(Enum):
MATCH_PIPELINE = 0
OFF = 1
BLINK = 2
ON = 3


class CamMode(Enum):
PROCESSED = 0
DRIVER = 1


class StreamMode(Enum):
STANDARD = 0
PIP_MAIN = 1
PIP_SECONDARY = 2


class SnapshotMode(Enum):
NONE = 0
TAKE_2_PS = 1


class Limelight:
_enabled = 1
_light = 1
Expand All @@ -32,8 +37,11 @@ class Limelight:
__nt = None
_active_pipeline = 0

def __init__(self, camera=False, light=False):
__nt = NetworkTables.getTable("limelight")
def __init__(self, nt=None, camera=False, light=False):
if nt:
__nt = nt
else:
__nt = NetworkTables.getTable("limelight")
self._enabled = camera
self._light = light

Expand Down Expand Up @@ -81,7 +89,7 @@ def target_area(self) -> float:
0% - 100% of image
"""
return self.__nt.getNumber("ta")

@property
def skew(self) -> float:
"""
Expand All @@ -91,7 +99,7 @@ def skew(self) -> float:
-90° - 0°
"""
return self.__nt.getNumber("ts")

@property
def latency(self) -> float:
"""
Expand All @@ -101,7 +109,7 @@ def latency(self) -> float:
Latency contribution
"""
return self.__nt.getNumber("tl")

@property
def bb_short(self) -> float:
"""
Expand All @@ -111,7 +119,7 @@ def bb_short(self) -> float:
Shortest sidelength
"""
return self.__nt.getNumber("tshort")

@property
def bb_long(self) -> float:
"""
Expand All @@ -121,7 +129,7 @@ def bb_long(self) -> float:
Longest sidelength
"""
return self.__nt.getNumber("tlong")

@property
def bb_horizontal(self) -> float:
"""
Expand All @@ -131,7 +139,7 @@ def bb_horizontal(self) -> float:
The horizontal sidelength
"""
return self.__nt.getNumber("thor")

@property
def bb_vertical(self) -> float:
"""
Expand All @@ -141,11 +149,11 @@ def bb_vertical(self) -> float:
The vertical sidelength
"""
return self.__nt.getNumber("tvert")

@property
def bounding_box(self) -> Tuple[float, float]:
return (self.bb_horizontal, self.bb_vertical)

def camtran(self) -> Tuple[Tuple[float, float, float], Tuple[float, float, float]]:
"""
Results of a 3D solution position, 6 numbers: Translation(x,y,z) Rotation(pitch, yaw, roll)
Expand All @@ -158,25 +166,28 @@ def crosshair_ax(self):
"""
Get crosshair A's X position
"""
return self.__nt.getNumber('cx0')
return self.__nt.getNumber("cx0")

@property
def crosshair_ay(self):
"""
Get crosshair A's Y position
"""
return self.__nt.getNumber('cy0')
return self.__nt.getNumber("cy0")

@property
def crosshair_bx(self):
"""
Get crosshair B's X position
"""
return self.__nt.getNumber('cx1')
return self.__nt.getNumber("cx1")

@property
def crosshair_by(self):
"""
Get crosshair B's Y position
"""
return self.__nt.getNumber('cy1')
return self.__nt.getNumber("cy1")

def camera(self, camMode: CamMode) -> None:
"""
Expand All @@ -187,7 +198,7 @@ def camera(self, camMode: CamMode) -> None:
"""
self._enabled = camMode
self.__nt.putNumber("camMode", camMode)

def light(self, status: LEDState) -> None:
"""
Set the status of the limelight lights
Expand All @@ -197,7 +208,7 @@ def light(self, status: LEDState) -> None:
"""
self._light = status
self.__nt.putNumber("ledMode", status)

def pipeline(self, pipeline):
"""
Sets the currently active pipeline
Expand All @@ -207,7 +218,7 @@ def pipeline(self, pipeline):
"""
self._active_pipeline = 0
self.__nt.putNumber("pipeline", pipeline)

def snapshot(self, snapshotMode: SnapshotMode):
"""
Allow users to take snapshots during a match
Expand All @@ -217,4 +228,3 @@ def snapshot(self, snapshotMode: SnapshotMode):
"""
self._snapshots = snapshotMode
self.__nt.putNumber("snapshot", snapshotMode)

21 changes: 16 additions & 5 deletions src/limelight_calcs.py → limelight/limelight_calcs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from limelight import Limelight
from .limelight import Limelight
import math

def calc_distance(camera_angle: float, mount_height: float, target_height: float, limelight: Limelight):

def calc_distance(
camera_angle: float, mount_height: float, target_height: float, limelight: Limelight
):
"""
Calculate the distance from the camera to the wall the target is mounted on
Expand All @@ -14,10 +17,15 @@ def calc_distance(camera_angle: float, mount_height: float, target_height: float
Returns:
Gives the distance (in the same units that were used for the input) away from the wall that has the target
"""
d = (known_height - target_height) / math.tan(math.radians(camera_angle + limelight.vertical_offset))
d = (target_height - mount_height) / math.tan(
math.radians(camera_angle + limelight.vertical_offset)
)
return d

def calc_camera_angle(x_distance: float, mount_height: float, target_height: float, limelight):

def calc_camera_angle(
x_distance: float, mount_height: float, target_height: float, limelight
):
"""
Calculate the camera's mounted angle from known properties. Set the robot to a fixed
distance away from the target and pass in the other properties and it will calculate
Expand All @@ -32,4 +40,7 @@ def calc_camera_angle(x_distance: float, mount_height: float, target_height: flo
Returns:
Gives the angle (in degrees) that the camera is mounted at
"""
a1 = math.degrees(-limelight.vertical_offset + math.atan(math.radians((target_height - mount_height)) / x_distance))
a1 = -limelight.vertical_offset + math.degrees(
math.atan((target_height - mount_height) / x_distance)
)
return a1
16 changes: 16 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from distutils.core import setup
import os


setup(
name="RobotPy Limelight",
version="2020.0.0",
author="Josh Bacon",
author_email="bacon.josh09@gmail.com",
packages=["limelight"],
url="https://pypi.org/project/robotpy-limelight",
license="LICENSE",
description="RobotPy Limelight utilities",
long_description=open("README.rst").read(),
install_requires=["pynetworktables >= " + os.environ["TRAVIS_TAG"]],
)
Binary file removed src/__pycache__/limelight.cpython-37.pyc
Binary file not shown.
Binary file removed src/__pycache__/limelight_calcs.cpython-37.pyc
Binary file not shown.
2 changes: 2 additions & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pynetworktables
pytest
22 changes: 22 additions & 0 deletions test/test_calcs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from unittest.mock import patch
from limelight.limelight import Limelight
from limelight.limelight_calcs import calc_distance, calc_camera_angle
import pytest


class MockLimelight(Limelight):
@property
def vertical_offset(self):
return 10.0


def test_calc_distance():
limelight = MockLimelight()
d = calc_distance(3, 2, 8, limelight)
assert abs(d - 25.988855) < 1e-4


def test_calc_camera_angle():
limelight = MockLimelight()
a1 = calc_camera_angle(10, 2, 8, limelight)
assert abs(a1 - 20.963780) < 1e-4

0 comments on commit a1fed9d

Please sign in to comment.