From c87ef96477e6f58b332fc870981aad7cc25e65e5 Mon Sep 17 00:00:00 2001 From: Danny Staple Date: Wed, 28 Dec 2022 11:27:16 +0000 Subject: [PATCH] Move the computer folder up - a bit easier to manage. Integrate fixes found in earlier examples. --- .../computer/display_from_robot.py | 89 -------- ch-13/full-version/computer/test_arena.py | 24 --- ..._motion_graph.py => display_from_robot.py} | 24 +-- .../{computer => }/find_devices.py | 0 ch-13/full-version/{computer => }/poetry.lock | 202 ++++++------------ .../{computer => }/pyproject.toml | 1 - .../{computer => }/render_distance_grid.py | 0 .../{computer => }/requirements.txt | 0 ch-13/full-version/robot/arena.py | 10 +- ch-13/full-version/robot/code.py | 177 +++++++-------- ch-13/full-version/robot/robot.py | 5 +- .../{computer => }/robot_ble_connection.py | 4 +- 12 files changed, 165 insertions(+), 371 deletions(-) delete mode 100644 ch-13/full-version/computer/display_from_robot.py delete mode 100644 ch-13/full-version/computer/test_arena.py rename ch-13/full-version/{computer/display_with_motion_graph.py => display_from_robot.py} (78%) rename ch-13/full-version/{computer => }/find_devices.py (100%) rename ch-13/full-version/{computer => }/poetry.lock (77%) rename ch-13/full-version/{computer => }/pyproject.toml (95%) rename ch-13/full-version/{computer => }/render_distance_grid.py (100%) rename ch-13/full-version/{computer => }/requirements.txt (100%) rename ch-13/full-version/{computer => }/robot_ble_connection.py (92%) diff --git a/ch-13/full-version/computer/display_from_robot.py b/ch-13/full-version/computer/display_from_robot.py deleted file mode 100644 index 0e5cd37..0000000 --- a/ch-13/full-version/computer/display_from_robot.py +++ /dev/null @@ -1,89 +0,0 @@ -import asyncio -import json -import numpy as np -import matplotlib.pyplot as plt -from matplotlib.widgets import Button - -from robot_ble_connection import BleConnection - - -class RobotDisplay: - def __init__(self): - self.ble_connection = BleConnection(self.handle_data) - self.line = "" - self.arena = {} - self.display_closed = False - self.fig, self.ax = plt.subplots() - self.poses = np.zeros([200, 3], dtype=np.int16) - self.motion = np.zeros([200, 3], dtype=float) - - def handle_close(self, _): - self.display_closed = True - - def handle_data(self, data): - self.line += data.decode("utf-8") - # print(f"Received data: {data.decode('utf-8')}") - # print(f"Line is now: {self.line}") - while "\n" in self.line: - line, self.line = self.line.split("\n", 1) - print(f"Received line: {line}") - try: - message = json.loads(line) - except ValueError: - print("Error parsing JSON") - return - if "arena" in message: - self.arena = message - if "poses" in message: - print(message) - incoming_poses = np.array(message["poses"], dtype=np.int16) - print("Incoming poses shape", incoming_poses.shape) - print("Existing poses shape", self.poses.shape) - self.poses[message["offset"]: message["offset"] + incoming_poses.shape[0]] = incoming_poses - if "motion" in message: - np.roll(self.motion, 1, axis=0) - self.motion[0] = [message["motion"]["rot1"], message["motion"]["trans"], message["motion"]["rot2"]] - - def draw(self): - self.ax.clear() - if self.arena: - for line in self.arena["arena"]: - self.ax.plot( - [line[0][0], line[1][0]], [line[0][1], line[1][1]], color="black" - ) - self.ax.scatter(self.poses[:,0], self.poses[:,1], color="blue") - - async def send_command(self, command): - #+ "\n" - why does adding this (which sounds right) cause the ble stack (on the robot or computer? ) not to work any more? - request = (json.dumps({"command": command}) ).encode() - print(f"Sending request: {request}") - await self.ble_connection.send_uart_data(request) - - def start(self, _): - self.button_task = asyncio.create_task(self.send_command("start")) - - # def stop(self, _): - # self.button_task = asyncio.create_task(self.send_command("stop")) - - async def main(self): - plt.ion() - await self.ble_connection.connect() - try: - await self.send_command("arena") - self.fig.canvas.mpl_connect("close_event", self.handle_close) - start_button = Button(plt.axes([0.7, 0.05, 0.1, 0.075]), "Start") - start_button.on_clicked(self.start) - # stop_button = Button(plt.axes([0.81, 0.05, 0.1, 0.075]), "Stop") - # stop_button.on_clicked(self.stop) - - while not self.display_closed: - self.draw() - plt.draw() - plt.pause(0.05) - await asyncio.sleep(0.01) - finally: - await self.ble_connection.close() - - -robot_display = RobotDisplay() -asyncio.run(robot_display.main()) diff --git a/ch-13/full-version/computer/test_arena.py b/ch-13/full-version/computer/test_arena.py deleted file mode 100644 index 8bbf6d3..0000000 --- a/ch-13/full-version/computer/test_arena.py +++ /dev/null @@ -1,24 +0,0 @@ -from unittest import TestCase -import math -import arena - -class TestArena(TestCase): - def test_get_point_to_distance_segment_1(self): - segment = ((0, 0), (0, 1500)) - for x in range(0, 1500): - for y in (0, 500, 1000): - self.assertEqual(arena.get_point_distance_to_segment(x, y, segment), x) - - def test_get_point_to_distance_segment_2(self): - segment = ((0, 0), (1500, 0)) - for y in range(0, 1500): - for x in (0, 500, 1000): - self.assertEqual(arena.get_point_distance_to_segment(x, y, segment), y) - - def test_get_point_distance_to_nearest_segment(self): - segments = [ - [(0, 1500), (1500, 1500)], - ] - for y in range(1500): - for x in (0, 500, 1000): - self.assertEqual(arena.get_point_distance_to_nearest_segment(segments, x, y), 1500 - y) diff --git a/ch-13/full-version/computer/display_with_motion_graph.py b/ch-13/full-version/display_from_robot.py similarity index 78% rename from ch-13/full-version/computer/display_with_motion_graph.py rename to ch-13/full-version/display_from_robot.py index 6486518..0a53a9d 100644 --- a/ch-13/full-version/computer/display_with_motion_graph.py +++ b/ch-13/full-version/display_from_robot.py @@ -10,23 +10,21 @@ from robot_ble_connection import BleConnection class RobotDisplay: def __init__(self): self.ble_connection = BleConnection(self.handle_data) - self.line = "" + self.buffer = "" self.arena = {} - self.display_closed = False + self.closed = False self.fig, self.ax = plt.subplots() - self.poses = np.zeros([200, 2], dtype=np.int16) + self.poses = np.zeros([20, 2], dtype=np.int16) self.motion = np.zeros([200, 3], dtype=float) def handle_close(self, _): - self.display_closed = True + self.closed = True def handle_data(self, data): - self.line += data.decode("utf-8") - # print(f"Received data: {data.decode('utf-8')}") - # print(f"Line is now: {self.line}") - while "\n" in self.line: - line, self.line = self.line.split("\n", 1) - print(f"Received line: {line}") + self.buffer += data.decode("utf-8") + while "\n" in self.buffer: + line, self.buffer = self.buffer.split("\n", 1) + print(f"Received data: {line}") try: message = json.loads(line) except ValueError: @@ -44,12 +42,10 @@ class RobotDisplay: for line in self.arena["arena"]: self.ax.plot( [line[0][0], line[1][0]], [line[0][1], line[1][1]], color="black" - ) + ) self.ax.scatter(self.poses[:,0], self.poses[:,1], color="blue") - async def send_command(self, command): - #+ "\n" - why does adding this (which sounds right) cause the ble stack (on the robot or computer? ) not to work any more? request = (json.dumps({"command": command}) ).encode() print(f"Sending request: {request}") await self.ble_connection.send_uart_data(request) @@ -70,7 +66,7 @@ class RobotDisplay: start_button.on_clicked(self.start) # stop_button = Button(plt.axes([0.81, 0.05, 0.1, 0.075]), "Stop") # stop_button.on_clicked(self.stop) - while not self.display_closed: + while not self.closed: self.draw() plt.draw() plt.pause(0.05) diff --git a/ch-13/full-version/computer/find_devices.py b/ch-13/full-version/find_devices.py similarity index 100% rename from ch-13/full-version/computer/find_devices.py rename to ch-13/full-version/find_devices.py diff --git a/ch-13/full-version/computer/poetry.lock b/ch-13/full-version/poetry.lock similarity index 77% rename from ch-13/full-version/computer/poetry.lock rename to ch-13/full-version/poetry.lock index 47cc3b7..a5e38b9 100644 --- a/ch-13/full-version/computer/poetry.lock +++ b/ch-13/full-version/poetry.lock @@ -8,7 +8,7 @@ python-versions = ">=3.6" [[package]] name = "black" -version = "22.10.0" +version = "22.12.0" description = "The uncompromising code formatter." category = "dev" optional = false @@ -99,7 +99,7 @@ python-versions = ">=3.6" [[package]] name = "dbus-fast" -version = "1.64.0" +version = "1.83.0" description = "A faster version of dbus-next" category = "main" optional = false @@ -158,14 +158,6 @@ pyparsing = ">=2.2.1" python-dateutil = ">=2.7" setuptools_scm = ">=7" -[[package]] -name = "msgpack" -version = "1.0.4" -description = "MessagePack serializer" -category = "main" -optional = false -python-versions = "*" - [[package]] name = "mypy-extensions" version = "0.4.3" @@ -184,18 +176,15 @@ python-versions = ">=3.8" [[package]] name = "packaging" -version = "21.3" +version = "22.0" description = "Core utilities for Python packages" category = "main" optional = false -python-versions = ">=3.6" - -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" +python-versions = ">=3.7" [[package]] name = "pathspec" -version = "0.10.1" +version = "0.10.3" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false @@ -215,15 +204,15 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "2.6.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.4)"] +test = ["appdirs (==1.4.4)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pyobjc-core" @@ -291,7 +280,7 @@ six = ">=1.5" [[package]] name = "setuptools" -version = "65.5.0" +version = "65.6.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false @@ -299,12 +288,12 @@ python-versions = ">=3.7" [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "setuptools-scm" -version = "7.0.5" +version = "7.1.0" description = "the blessed package to manage your versions by scm tags" category = "main" optional = false @@ -313,7 +302,7 @@ python-versions = ">=3.7" [package.dependencies] packaging = ">=20.0" setuptools = "*" -tomli = ">=1.0.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} typing-extensions = "*" [package.extras] @@ -347,7 +336,7 @@ python-versions = ">=3.7" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "a2ae390fc260b23b2aea772611acac3c8626867abcb0e477875407c9f24a5fa6" +content-hash = "4ec6eb3464cbb49afad347e67bdf7c353d7ea4030fd8ed4257098a5df334eb99" [metadata.files] async-timeout = [ @@ -355,27 +344,18 @@ async-timeout = [ {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, ] black = [ - {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, - {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, - {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, - {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"}, - {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"}, - {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"}, - {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, - {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, - {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"}, - {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, - {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, - {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, - {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, - {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"}, - {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, - {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, - {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"}, - {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, - {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, - {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, - {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, + {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, + {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, + {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, + {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, + {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, + {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, + {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, + {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, + {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, + {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, + {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, + {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, ] bleak = [ {file = "bleak-0.19.0-py3-none-any.whl", hash = "sha256:ccdba0d17dcceb1326e4e46600b37e9019cd52ce01948e2a3dbd6c94d1e4de01"}, @@ -478,34 +458,34 @@ cycler = [ {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, ] dbus-fast = [ - {file = "dbus_fast-1.64.0-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:d6ee2acd48a6f22836a0782786c0f617a70bd33353100028a26b351e653c83a4"}, - {file = "dbus_fast-1.64.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff97c83a30ccf9ffe43df1721f0bff90fdfbe39a583c77a52932046b5f707b9c"}, - {file = "dbus_fast-1.64.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6d912844d3763140fdb4d9c474d1d86e8129c9a498e1cbcdf54ac71811a081df"}, - {file = "dbus_fast-1.64.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:48248467c8cc25af0bf42676f337ee8b56a2c8c3b9df1eb7a51f649e74401343"}, - {file = "dbus_fast-1.64.0-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:f44e5b3025db2f0c689afc34478fa3d522c45af5721aacebcfc4c3e9c268b23a"}, - {file = "dbus_fast-1.64.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:939417ecc4ea438ba9287f2a8df92329eb87179c69f627d3eb27af609ac59446"}, - {file = "dbus_fast-1.64.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3cace85b55be5f82f2bb51f98d834f92e572668a05f6492e96ea90a8728a2983"}, - {file = "dbus_fast-1.64.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fa2e77bef181d3e9f72176ad750da2b448b2000238cef56dafa1b08093a78a90"}, - {file = "dbus_fast-1.64.0-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:5b04c84d0345fba5ceb6bb56bfa5c3f34a3a9995a2d1ea17857c1e2e50cc4a26"}, - {file = "dbus_fast-1.64.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72275f7054c683b2c340d0a6baf922fa0d0cef9ec00cb2262d2242d3c428b8d8"}, - {file = "dbus_fast-1.64.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b235c111dd9746f3d2a4c2ce1f9d7c255fe6ba64537551154d10599f9aef279c"}, - {file = "dbus_fast-1.64.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:fad7108eddd552ccca7a7b49bd61848bc6936bdaf1dd9a4e4c6b031c25b61c9c"}, - {file = "dbus_fast-1.64.0-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:76301537ebf0ca4fe9b42f1463038386728d5655817639b1f62737126f85ed09"}, - {file = "dbus_fast-1.64.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99eda460d32673d1261cfa9422d356f5d09dc10dd094158a9e8e19903991af3c"}, - {file = "dbus_fast-1.64.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:78cee1896db352fbddac0c3eb91f0c97f93627b6f010b4987ac0b724a88020fa"}, - {file = "dbus_fast-1.64.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:660f824f3a13d5b18140ee356823ae0fb263d4c182451130fd2b1e594b9bad1a"}, - {file = "dbus_fast-1.64.0-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:838254b626427d919c652fe3fc5841a6c6f20b3c12e5335d7d32124111161461"}, - {file = "dbus_fast-1.64.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb73f5a364ab22151892d349991ae57a3d4e18fa4c6a6d0134f5a0b8cfaefc8"}, - {file = "dbus_fast-1.64.0-cp39-cp39-manylinux_2_31_x86_64.whl", hash = "sha256:c0d3e18a2b793e7e774773190db631b729bd7ca0b88c63415e286fbe7f4c8320"}, - {file = "dbus_fast-1.64.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a0a4e64ac5a994239cb1200cfc7ce9d2173233c9a5f3f48dca3bf3ca3e8e132a"}, - {file = "dbus_fast-1.64.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27260f6998f614dfb9c9fa2c9674402134e8a221b57f52a7dfecce2bed2df37"}, - {file = "dbus_fast-1.64.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:735feead084951a1daf9c71480f4bfe84b127cacd9af0fddf70cdf7043f7a29c"}, - {file = "dbus_fast-1.64.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:025583c613beb58abd24e993e3be6098002eac9d01afff1e7180e5ddbbf74772"}, - {file = "dbus_fast-1.64.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:09488197ffc535ad62d048e532e127d12e4878a3af8b7cd5cf34819f1bd6ddca"}, - {file = "dbus_fast-1.64.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9d395687bcd0098cdacdfb8c1897c81998aabd07c13dd599e8fa2e73f04f704"}, - {file = "dbus_fast-1.64.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:830f028efa0753f6833a7f6491789436cfc63debdfac697465e334f3dd7c14d6"}, - {file = "dbus_fast-1.64.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d2cec285c42c1fe4921ae879e975693376bd9c815494c354aa1b63fb40bbfaf"}, - {file = "dbus_fast-1.64.0.tar.gz", hash = "sha256:794d67fc6369962bb291edf68c76a4b10a5f019c6c9b0458ca22c0d318cea659"}, + {file = "dbus_fast-1.83.0-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:41fd66ed9298869f135c43a6f22f3790d4b765a6a593fb415322e4dabe6f5452"}, + {file = "dbus_fast-1.83.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dedfbede7c7fc3d026014e5eedaf67b58c91806c86e435896c37060d9afac6c4"}, + {file = "dbus_fast-1.83.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3445f2e3377f30d2d24de7b5dd378d18ce71263ec96c932cd1abea5396440a2a"}, + {file = "dbus_fast-1.83.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:40189a5f578fca92251bfecb4a26da3f7752f0db52b6bcff9784407d45232d2e"}, + {file = "dbus_fast-1.83.0-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:822e58c7d530b8b4dc79a54fe1718cda78feab9d64e8f6623f3a0b477b6443a3"}, + {file = "dbus_fast-1.83.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc5c48ac4472ec5ba059a29e95328d06e224b03d5b0d5f1e1cd718213aa324d0"}, + {file = "dbus_fast-1.83.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ca4aad792dd1fce92bc4da353f424db3195bd5f8750e1c98c27ed49bec0f650b"}, + {file = "dbus_fast-1.83.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d428b34bdd6eb7bb35a9ca750530e8ef675e056de2ad4551bc56850264e18d35"}, + {file = "dbus_fast-1.83.0-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b053c4c2f2ca4c0f0f6928346b621f2cac77f08c03a8ced530d47c2faa46408b"}, + {file = "dbus_fast-1.83.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2ccf9563b6a926d46d0b546e57526556c24848127e9997a868e78d16f150297"}, + {file = "dbus_fast-1.83.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a79c27ed8bb71c89c557398b61bb53d60f4d1de1c52c33386b8504ec65b0a299"}, + {file = "dbus_fast-1.83.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:94c9ec8b3639cee94691e5788d6db6a5b502834968888f1a8be38fd0c4806e7c"}, + {file = "dbus_fast-1.83.0-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:5ca89e42bba8954f75eca52a3f2d1e3ecf6bbf19f17c543de122ccf82dabb65b"}, + {file = "dbus_fast-1.83.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9c87ab1546a38b5a2b4170fb9eee2e40ef82961b714eefa46674f066b255ff1"}, + {file = "dbus_fast-1.83.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7283ff647b1dff8cdbd98edda8d73c86e4d619f774ad574c72fb8c8056baadfa"}, + {file = "dbus_fast-1.83.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1f9b6ea977feeb816f5d74578d67ac713a8134726257112693ed685e975585d3"}, + {file = "dbus_fast-1.83.0-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:5b12f018d6fedf0ffba3d8e2d25a1f436c4b100c95d925e6cea8c2aceb475fed"}, + {file = "dbus_fast-1.83.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3491e38e58bc1c4aeab67994b5bba6d663c0d8999d3a1f5aae23afe392d6099"}, + {file = "dbus_fast-1.83.0-cp39-cp39-manylinux_2_31_x86_64.whl", hash = "sha256:4306b87f88546d9645b6b1ccdc863e410798c1c1ad7312ed6b210aa8a1b23dde"}, + {file = "dbus_fast-1.83.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:463ea272c36cc55dc4d3b3d55d17738fd06c1f870c5d9f2d5727c50554461aa5"}, + {file = "dbus_fast-1.83.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6f0b9e74e190a10a93a3831c91b7289bedbcd51dc20aa4326ee723e89bf12c26"}, + {file = "dbus_fast-1.83.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:f6c82bc159817f4ded469ca75af79bdb1b94699546232ea8b43c809cb1b157c2"}, + {file = "dbus_fast-1.83.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fb9eaed1af93b021e45e6b4dec0fbbba7ab7de6710c890df486a9aa2de1851b"}, + {file = "dbus_fast-1.83.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:cce251b7e7ebbdbc858abc2eaed781bda44999ec61ed77c637da0384eb74a0a0"}, + {file = "dbus_fast-1.83.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50729191ff9045566f960142c1b7ef284178924fc514d71f92e5a9486d83267d"}, + {file = "dbus_fast-1.83.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:4a4c1bca00c7b7fde4b72e4f8553c3d42d8459dcf475f94a7ffd8eab56e6ae9b"}, + {file = "dbus_fast-1.83.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88697f7b1616aa980e59648d469edba30a46393a23155c3246d7e2a7224bbbd6"}, + {file = "dbus_fast-1.83.0.tar.gz", hash = "sha256:6a1a96725f1c91157fab94ab0bf2a5ddfdf0ed5fb68510980698d8180f51c848"}, ] fonttools = [ {file = "fonttools-4.38.0-py3-none-any.whl", hash = "sha256:820466f43c8be8c3009aef8b87e785014133508f0de64ec469e4efb643ae54fb"}, @@ -624,60 +604,6 @@ matplotlib = [ {file = "matplotlib-3.6.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5f97141e05baf160c3ec125f06ceb2a44c9bb62f42fcb8ee1c05313c73e99432"}, {file = "matplotlib-3.6.1.tar.gz", hash = "sha256:e2d1b7225666f7e1bcc94c0bc9c587a82e3e8691da4757e357e5c2515222ee37"}, ] -msgpack = [ - {file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4ab251d229d10498e9a2f3b1e68ef64cb393394ec477e3370c457f9430ce9250"}, - {file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:112b0f93202d7c0fef0b7810d465fde23c746a2d482e1e2de2aafd2ce1492c88"}, - {file = "msgpack-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:002b5c72b6cd9b4bafd790f364b8480e859b4712e91f43014fe01e4f957b8467"}, - {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35bc0faa494b0f1d851fd29129b2575b2e26d41d177caacd4206d81502d4c6a6"}, - {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4733359808c56d5d7756628736061c432ded018e7a1dff2d35a02439043321aa"}, - {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb514ad14edf07a1dbe63761fd30f89ae79b42625731e1ccf5e1f1092950eaa6"}, - {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c23080fdeec4716aede32b4e0ef7e213c7b1093eede9ee010949f2a418ced6ba"}, - {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:49565b0e3d7896d9ea71d9095df15b7f75a035c49be733051c34762ca95bbf7e"}, - {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:aca0f1644d6b5a73eb3e74d4d64d5d8c6c3d577e753a04c9e9c87d07692c58db"}, - {file = "msgpack-1.0.4-cp310-cp310-win32.whl", hash = "sha256:0dfe3947db5fb9ce52aaea6ca28112a170db9eae75adf9339a1aec434dc954ef"}, - {file = "msgpack-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dea20515f660aa6b7e964433b1808d098dcfcabbebeaaad240d11f909298075"}, - {file = "msgpack-1.0.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e83f80a7fec1a62cf4e6c9a660e39c7f878f603737a0cdac8c13131d11d97f52"}, - {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c11a48cf5e59026ad7cb0dc29e29a01b5a66a3e333dc11c04f7e991fc5510a9"}, - {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1276e8f34e139aeff1c77a3cefb295598b504ac5314d32c8c3d54d24fadb94c9"}, - {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c9566f2c39ccced0a38d37c26cc3570983b97833c365a6044edef3574a00c08"}, - {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fcb8a47f43acc113e24e910399376f7277cf8508b27e5b88499f053de6b115a8"}, - {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:76ee788122de3a68a02ed6f3a16bbcd97bc7c2e39bd4d94be2f1821e7c4a64e6"}, - {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0a68d3ac0104e2d3510de90a1091720157c319ceeb90d74f7b5295a6bee51bae"}, - {file = "msgpack-1.0.4-cp36-cp36m-win32.whl", hash = "sha256:85f279d88d8e833ec015650fd15ae5eddce0791e1e8a59165318f371158efec6"}, - {file = "msgpack-1.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:c1683841cd4fa45ac427c18854c3ec3cd9b681694caf5bff04edb9387602d661"}, - {file = "msgpack-1.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a75dfb03f8b06f4ab093dafe3ddcc2d633259e6c3f74bb1b01996f5d8aa5868c"}, - {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9667bdfdf523c40d2511f0e98a6c9d3603be6b371ae9a238b7ef2dc4e7a427b0"}, - {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11184bc7e56fd74c00ead4f9cc9a3091d62ecb96e97653add7a879a14b003227"}, - {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac5bd7901487c4a1dd51a8c58f2632b15d838d07ceedaa5e4c080f7190925bff"}, - {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1e91d641d2bfe91ba4c52039adc5bccf27c335356055825c7f88742c8bb900dd"}, - {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2a2df1b55a78eb5f5b7d2a4bb221cd8363913830145fad05374a80bf0877cb1e"}, - {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:545e3cf0cf74f3e48b470f68ed19551ae6f9722814ea969305794645da091236"}, - {file = "msgpack-1.0.4-cp37-cp37m-win32.whl", hash = "sha256:2cc5ca2712ac0003bcb625c96368fd08a0f86bbc1a5578802512d87bc592fe44"}, - {file = "msgpack-1.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:eba96145051ccec0ec86611fe9cf693ce55f2a3ce89c06ed307de0e085730ec1"}, - {file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7760f85956c415578c17edb39eed99f9181a48375b0d4a94076d84148cf67b2d"}, - {file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:449e57cc1ff18d3b444eb554e44613cffcccb32805d16726a5494038c3b93dab"}, - {file = "msgpack-1.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d603de2b8d2ea3f3bcb2efe286849aa7a81531abc52d8454da12f46235092bcb"}, - {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f5d88c99f64c456413d74a975bd605a9b0526293218a3b77220a2c15458ba9"}, - {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916c78f33602ecf0509cc40379271ba0f9ab572b066bd4bdafd7434dee4bc6e"}, - {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81fc7ba725464651190b196f3cd848e8553d4d510114a954681fd0b9c479d7e1"}, - {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5b5b962221fa2c5d3a7f8133f9abffc114fe218eb4365e40f17732ade576c8e"}, - {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:77ccd2af37f3db0ea59fb280fa2165bf1b096510ba9fe0cc2bf8fa92a22fdb43"}, - {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b17be2478b622939e39b816e0aa8242611cc8d3583d1cd8ec31b249f04623243"}, - {file = "msgpack-1.0.4-cp38-cp38-win32.whl", hash = "sha256:2bb8cdf50dd623392fa75525cce44a65a12a00c98e1e37bf0fb08ddce2ff60d2"}, - {file = "msgpack-1.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:26b8feaca40a90cbe031b03d82b2898bf560027160d3eae1423f4a67654ec5d6"}, - {file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:462497af5fd4e0edbb1559c352ad84f6c577ffbbb708566a0abaaa84acd9f3ae"}, - {file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2999623886c5c02deefe156e8f869c3b0aaeba14bfc50aa2486a0415178fce55"}, - {file = "msgpack-1.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f0029245c51fd9473dc1aede1160b0a29f4a912e6b1dd353fa6d317085b219da"}, - {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed6f7b854a823ea44cf94919ba3f727e230da29feb4a99711433f25800cf747f"}, - {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0df96d6eaf45ceca04b3f3b4b111b86b33785683d682c655063ef8057d61fd92"}, - {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a4192b1ab40f8dca3f2877b70e63799d95c62c068c84dc028b40a6cb03ccd0f"}, - {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e3590f9fb9f7fbc36df366267870e77269c03172d086fa76bb4eba8b2b46624"}, - {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1576bd97527a93c44fa856770197dec00d223b0b9f36ef03f65bac60197cedf8"}, - {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63e29d6e8c9ca22b21846234913c3466b7e4ee6e422f205a2988083de3b08cae"}, - {file = "msgpack-1.0.4-cp39-cp39-win32.whl", hash = "sha256:fb62ea4b62bfcb0b380d5680f9a4b3f9a2d166d9394e9bbd9666c0ee09a3645c"}, - {file = "msgpack-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4d5834a2a48965a349da1c5a79760d94a1a0172fbb5ab6b5b33cbf8447e109ce"}, - {file = "msgpack-1.0.4.tar.gz", hash = "sha256:f5d869c18f030202eb412f08b28d2afeea553d6613aee89e200d7aca7ef01f5f"}, -] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, @@ -713,12 +639,12 @@ numpy = [ {file = "numpy-1.23.4.tar.gz", hash = "sha256:ed2cc92af0efad20198638c69bb0fc2870a58dabfba6eb722c933b48556c686c"}, ] packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, + {file = "packaging-22.0-py3-none-any.whl", hash = "sha256:957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3"}, + {file = "packaging-22.0.tar.gz", hash = "sha256:2198ec20bd4c017b8f9717e00f0c8714076fc2fd93816750ab48e2c41de2cfd3"}, ] pathspec = [ - {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, - {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, + {file = "pathspec-0.10.3-py3-none-any.whl", hash = "sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6"}, + {file = "pathspec-0.10.3.tar.gz", hash = "sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6"}, ] Pillow = [ {file = "Pillow-9.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:0b7257127d646ff8676ec8a15520013a698d1fdc48bc2a79ba4e53df792526f2"}, @@ -782,8 +708,8 @@ Pillow = [ {file = "Pillow-9.3.0.tar.gz", hash = "sha256:c935a22a557a560108d780f9a0fc426dd7459940dc54faa49d83249c8d3e760f"}, ] platformdirs = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, + {file = "platformdirs-2.6.0-py3-none-any.whl", hash = "sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca"}, + {file = "platformdirs-2.6.0.tar.gz", hash = "sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e"}, ] pyobjc-core = [ {file = "pyobjc-core-8.5.1.tar.gz", hash = "sha256:f8592a12de076c27006700c4a46164478564fa33d7da41e7cbdd0a3bf9ddbccf"}, @@ -830,12 +756,12 @@ python-dateutil = [ {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] setuptools = [ - {file = "setuptools-65.5.0-py3-none-any.whl", hash = "sha256:f62ea9da9ed6289bfe868cd6845968a2c854d1427f8548d52cae02a42b4f0356"}, - {file = "setuptools-65.5.0.tar.gz", hash = "sha256:512e5536220e38146176efb833d4a62aa726b7bbff82cfbc8ba9eaa3996e0b17"}, + {file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"}, + {file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"}, ] setuptools-scm = [ - {file = "setuptools_scm-7.0.5-py3-none-any.whl", hash = "sha256:7930f720905e03ccd1e1d821db521bff7ec2ac9cf0ceb6552dd73d24a45d3b02"}, - {file = "setuptools_scm-7.0.5.tar.gz", hash = "sha256:031e13af771d6f892b941adb6ea04545bbf91ebc5ce68c78aaf3fff6e1fb4844"}, + {file = "setuptools_scm-7.1.0-py3-none-any.whl", hash = "sha256:73988b6d848709e2af142aa48c986ea29592bbcfca5375678064708205253d8e"}, + {file = "setuptools_scm-7.1.0.tar.gz", hash = "sha256:6c508345a771aad7d56ebff0e70628bf2b0ec7573762be9960214730de278f27"}, ] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, diff --git a/ch-13/full-version/computer/pyproject.toml b/ch-13/full-version/pyproject.toml similarity index 95% rename from ch-13/full-version/computer/pyproject.toml rename to ch-13/full-version/pyproject.toml index 1571d56..e5ac640 100644 --- a/ch-13/full-version/computer/pyproject.toml +++ b/ch-13/full-version/pyproject.toml @@ -11,7 +11,6 @@ python = "^3.9" matplotlib = "3.6.1" numpy = "1.23.4" bleak = "0.19.0" -msgpack = "^1.0.4" [tool.poetry.group.dev.dependencies] diff --git a/ch-13/full-version/computer/render_distance_grid.py b/ch-13/full-version/render_distance_grid.py similarity index 100% rename from ch-13/full-version/computer/render_distance_grid.py rename to ch-13/full-version/render_distance_grid.py diff --git a/ch-13/full-version/computer/requirements.txt b/ch-13/full-version/requirements.txt similarity index 100% rename from ch-13/full-version/computer/requirements.txt rename to ch-13/full-version/requirements.txt diff --git a/ch-13/full-version/robot/arena.py b/ch-13/full-version/robot/arena.py index 6aeb29c..b4e8a98 100644 --- a/ch-13/full-version/robot/arena.py +++ b/ch-13/full-version/robot/arena.py @@ -1,4 +1,4 @@ -"""Represent the lines and target zone of the arena""" +"""Represent the lines of the arena""" try: from ulab import numpy as np except ImportError: @@ -16,8 +16,7 @@ boundary_lines = [ width = 1500 height = 1500 -# need to state clearly the orientation of the heading -# if coordinates 0, 0 is bottom left, then heading 0 is right, with heading increasing anticlockwise. +# 0, 0 is bottom left. Heading 0 is right, with heading increasing anticlockwise. Standard position angles. def point_is_inside_arena(x, y): """Return True if the point is inside the arena. @@ -67,11 +66,12 @@ def make_distance_grid(): """Take the boundary lines. With and overscan of 10 cells, and grid cell size of 5cm (50mm), make a grid of the distance to the nearest boundary line. """ - grid = np.zeros((width // grid_cell_size + 2 * overscan, height // grid_cell_size + 2 * overscan), dtype=np.float) + grid = np.zeros((width // grid_cell_size + 2 * overscan, height // grid_cell_size + 2 * overscan), dtype=np.uint8) + # 4kb as floats, 1 kb as uint8s. for x in range(grid.shape[0]): column_x = x * grid_cell_size - (overscan * grid_cell_size) for y in range(grid.shape[1]): - value = get_point_decay_from_nearest_segment(boundary_lines, column_x, y * grid_cell_size - (overscan * grid_cell_size)) + value = int(get_point_decay_from_nearest_segment(boundary_lines, column_x, y * grid_cell_size - (overscan * grid_cell_size)) * 255) grid[x, y] = value return grid diff --git a/ch-13/full-version/robot/code.py b/ch-13/full-version/robot/code.py index 0caabdd..83b364f 100644 --- a/ch-13/full-version/robot/code.py +++ b/ch-13/full-version/robot/code.py @@ -2,34 +2,49 @@ import asyncio import json import random from ulab import numpy as np + import arena import robot -class CollisionAvoid: +class DistanceSensorTracker: def __init__(self): + robot.left_distance.distance_mode = 2 + robot.right_distance.distance_mode = 2 + robot.left_distance.timing_budget = 50 + robot.right_distance.timing_budget = 50 + self.left = 300 + self.right = 300 + + async def main(self): + robot.left_distance.start_ranging() + robot.right_distance.start_ranging() + while True: + if robot.left_distance.data_ready and robot.left_distance.distance: + self.left = robot.left_distance.distance * 10 # convert to mm + robot.left_distance.clear_interrupt() + if robot.right_distance.data_ready and robot.right_distance.distance: + self.right = robot.right_distance.distance * 10 + robot.right_distance.clear_interrupt() + await asyncio.sleep(0.01) + + +class CollisionAvoid: + def __init__(self, distance_sensors): self.speed = 0.6 - self.left_distance = 300 - self.right_distance = 300 + self.distance_sensors = distance_sensors - def update(self, left_distance, right_distance): - self.left_distance = left_distance - self.right_distance = right_distance - - async def run(self): + async def main(self): while True: robot.set_right(self.speed) - while self.left_distance < 300 or self.right_distance < 300: - robot.set_left(-0.6) + while self.distance_sensors.left < 300 or \ + self.distance_sensors.right < 300: + robot.set_left(-self.speed) await asyncio.sleep(0.3) robot.set_left(self.speed) await asyncio.sleep(0) - -triangular_proportion = np.sqrt(6) / 2 -def get_triangular_sample(mean, standard_deviation): - base = triangular_proportion * (random.uniform(-standard_deviation, standard_deviation) + random.uniform(-standard_deviation, standard_deviation)) - return mean + base - +def get_scaled_sample_around_mean(mean, scale): + return mean + (random.uniform(-scale, scale) + random.uniform(-scale, scale)) / 2 def convert_to_standard_position(true_bearing): standard_position = 90 - true_bearing @@ -43,22 +58,29 @@ def convert_to_standard_position(true_bearing): def send_json(data): robot.uart.write((json.dumps(data) + "\n").encode()) +def read_json(): + try: + data = robot.uart.readline() + decoded = data.decode() + return json.loads(decoded) + except (UnicodeError, ValueError): + print("Invalid data") + return None + def send_poses(samples): send_json({ - "poses": samples[:,:2].tolist(), + "poses": np.array(samples[:,:2], dtype=np.int16).tolist(), }) class Simulation: def __init__(self): - self.population_size = 300 - self.left_distance = 100 - self.right_distance = 100 + self.population_size = 200 self.imu_mix = 0.3 * 0.5 self.encoder_mix = 0.7 - self.rotation_standard_dev = 2 # degrees - self.speed_standard_dev = 5 # mm + self.rotation_scale = 0.5 # degrees + self.speed_scale = 3 # mm # Poses - each an array of [x, y, heading] self.poses = np.array( @@ -66,9 +88,12 @@ class Simulation: int(random.uniform(0, arena.width)), int(random.uniform(0, arena.height)), int(random.uniform(0, 360))) for _ in range(self.population_size)], - dtype=np.int16, + dtype=np.float, ) - self.collision_avoider = CollisionAvoid() + self.distance_sensors = DistanceSensorTracker() + self.collision_avoider = CollisionAvoid(self.distance_sensors) + self.last_encoder_left = robot.left_encoder.read() + self.last_encoder_right = robot.right_encoder.read() async def apply_sensor_model(self): # Based on vl53l1x sensor readings, create weight for each pose. @@ -90,15 +115,15 @@ class Simulation: distance_sensor_left[:, 0] = self.poses[:, 0] + np.cos(poses_left_90) * robot.distance_sensor_from_middle distance_sensor_left[:, 1] = self.poses[:, 1] + np.sin(poses_left_90) * robot.distance_sensor_from_middle # now project forward by distance sensor range - distance_sensor_left[:, 0] += np.cos(self.poses[:, 2]) * self.left_distance - distance_sensor_left[:, 1] += np.sin(self.poses[:, 2]) * self.left_distance + distance_sensor_left[:, 0] += np.cos(self.poses[:, 2]) * self.distance_sensors.left + distance_sensor_left[:, 1] += np.sin(self.poses[:, 2]) * self.distance_sensors.left # right sensor poses_right_90 = np.radians(self.poses[:, 2] - 90) distance_sensor_right[:, 0] = self.poses[:, 0] + np.cos(poses_right_90) * robot.distance_sensor_from_middle distance_sensor_right[:, 1] = self.poses[:, 1] + np.sin(poses_right_90) * robot.distance_sensor_from_middle # now project forward by distance sensor range - distance_sensor_right[:, 0] += np.cos(self.poses[:, 2]) * self.left_distance - distance_sensor_right[:, 1] += np.sin(self.poses[:, 2]) * self.left_distance + distance_sensor_right[:, 0] += np.cos(self.poses[:, 2]) * self.distance_sensors.right + distance_sensor_right[:, 1] += np.sin(self.poses[:, 2]) * self.distance_sensors.right await asyncio.sleep(0) # weighted poses a numpy array of weights for each pose @@ -134,15 +159,14 @@ class Simulation: return np.array([self.poses[n] for n in samples]) def convert_odometry_to_motion(self, left_encoder_delta, right_encoder_delta): - # convert odometry to motion - # left_encoder is the change in the left encoder - # right_encoder is the change in the right encoder - # returns rot1, trans, rot2 - # rot1 is the rotation of the robot in radians before the translation - # trans is the distance the robot has moved in mm - # rot2 is the rotation of the robot in radians - - # convert encoder counts to mm + """ + left_encoder is the change in the left encoder + right_encoder is the change in the right encoder + returns rot1, trans, rot2 + rot1 is the rotation of the robot in degrees before the translation + trans is the distance the robot has moved in mm + rot2 is the rotation of the robot in degrees + """ left_mm = left_encoder_delta * robot.ticks_to_mm right_mm = right_encoder_delta * robot.ticks_to_mm @@ -150,13 +174,13 @@ class Simulation: # no rotation return 0, left_mm, 0 - # calculate the ICC + # calculate the radius of the arc radius = (robot.wheelbase_mm / 2) * (left_mm + right_mm) / (right_mm - left_mm) - ## arc length/radius = angle - theta = (right_mm - left_mm) / robot.wheelbase_mm + ## angle = difference in steps / wheelbase + d_theta = (right_mm - left_mm) / robot.wheelbase_mm # For a small enough motion, assume that the chord length = arc length - arc_length = theta * radius - rot1 = np.degrees(theta/2) + arc_length = d_theta * radius + rot1 = np.degrees(d_theta/2) rot2 = rot1 return rot1, arc_length, rot2 @@ -166,10 +190,9 @@ class Simulation: new_encoder_left = robot.left_encoder.read() new_encoder_right = robot.right_encoder.read() - await asyncio.sleep(0) rot1, trans, rot2 = self.convert_odometry_to_motion( new_encoder_left - self.last_encoder_left, - new_encoder_right - self.last_encoder_right) + new_encoder_right - self.last_encoder_right) self.last_encoder_left = new_encoder_left self.last_encoder_right = new_encoder_right try: @@ -186,67 +209,32 @@ class Simulation: rot2 = rot2 * self.encoder_mix + heading_change * self.imu_mix else: print("Failed to get heading") - await asyncio.sleep(0) - rot1_model = np.array([get_triangular_sample(rot1, self.rotation_standard_dev) for _ in range(self.poses.shape[0])]) - trans_model = np.array([get_triangular_sample(trans, self.speed_standard_dev) for _ in range(self.poses.shape[0])]) - rot2_model = np.array([get_triangular_sample(rot2, self.rotation_standard_dev) for _ in range(self.poses.shape[0])]) + await asyncio.sleep(0) + rot1_model = np.array([get_scaled_sample_around_mean(rot1, self.rotation_scale) for _ in range(self.poses.shape[0])]) + trans_model = np.array([get_scaled_sample_around_mean(trans, self.speed_scale) for _ in range(self.poses.shape[0])]) + rot2_model = np.array([get_scaled_sample_around_mean(rot2, self.rotation_scale) for _ in range(self.poses.shape[0])]) self.poses[:,2] += rot1_model rot1_radians = np.radians(self.poses[:,2]) self.poses[:,0] += trans_model * np.cos(rot1_radians) self.poses[:,1] += trans_model * np.sin(rot1_radians) self.poses[:,2] += rot2_model - self.poses[:,2] = np.vectorize(lambda n: float(n % 360))(self.poses[:,2]) - self.poses = np.array(self.poses, dtype=np.int16) + self.poses[:,2] = np.array([float(theta % 360) for theta in self.poses[:,2]]) - async def distance_sensor_updater(self): - robot.left_distance.distance_mode = 2 - robot.right_distance.distance_mode = 2 - robot.left_distance.timing_budget = 50 - robot.right_distance.timing_budget = 50 - robot.left_distance.start_ranging() - robot.right_distance.start_ranging() - while True: - if robot.left_distance.data_ready and robot.left_distance.distance: - self.left_distance = robot.left_distance.distance * 10 # convert to mm - robot.left_distance.clear_interrupt() - if robot.right_distance.data_ready and robot.right_distance.distance: - self.right_distance = robot.right_distance.distance * 10 - robot.right_distance.clear_interrupt() - self.collision_avoider.update(self.left_distance, self.right_distance) - await asyncio.sleep(0.01) - - async def run(self): - asyncio.create_task(self.distance_sensor_updater()) - asyncio.create_task(self.collision_avoider.run()) + async def main(self): + asyncio.create_task(self.distance_sensors.main()) + asyncio.create_task(self.collision_avoider.main()) self.last_heading = robot.imu.euler[0] - self.last_encoder_left = robot.left_encoder.read() - self.last_encoder_right = robot.right_encoder.read() - try: while True: weights = await self.apply_sensor_model() send_poses(self.resample(weights, 20)) self.poses = self.resample(weights, self.population_size) + await asyncio.sleep(0) await self.motion_model() finally: robot.stop() -def read_command(): - data = robot.uart.readline() - try: - decoded = data.decode() - except UnicodeError: - print("UnicodeError decoding :") - print(data) - return None - try: - request = json.loads(decoded) - except ValueError: - print("ValueError reading json from:") - print(decoded) - return None - return request async def updater(simulation): @@ -274,21 +262,20 @@ async def command_handler(simulation): while True: if robot.uart.in_waiting: print("Receiving data...") - request = read_command() + request = read_json() if not request: print("no request") continue + print("Received: ", request) if request["command"] == "arena": - send_json( - { - "arena": arena.boundary_lines - } - ) + send_json({ + "arena": arena.boundary_lines, + }) if not update_task: update_task = asyncio.create_task(updater(simulation)) elif request["command"] == "start": if not simulation_task: - simulation_task = asyncio.create_task(simulation.run()) + simulation_task = asyncio.create_task(simulation.main()) await asyncio.sleep(0.1) diff --git a/ch-13/full-version/robot/robot.py b/ch-13/full-version/robot/robot.py index 497d0b5..68bd714 100755 --- a/ch-13/full-version/robot/robot.py +++ b/ch-13/full-version/robot/robot.py @@ -4,7 +4,6 @@ import pio_encoder import busio import adafruit_vl53l1x import math -import busio import adafruit_bno055 uart = busio.UART(board.GP12, board.GP13, baudrate=9600) @@ -18,6 +17,7 @@ ticks_to_mm = wheel_circumference_mm / ticks_per_revolution ticks_to_m = ticks_to_mm / 1000 m_to_ticks = 1 / ticks_to_m wheelbase_mm = 170 +distance_sensor_from_middle = 40 # approx mm motor_A2 = pwmio.PWMOut(board.GP17, frequency=100) motor_A1 = pwmio.PWMOut(board.GP16, frequency=100) @@ -36,10 +36,7 @@ i2c1 = busio.I2C(sda=board.GP2, scl=board.GP3) left_distance = adafruit_vl53l1x.VL53L1X(i2c0) right_distance = adafruit_vl53l1x.VL53L1X(i2c1) -distance_sensor_from_middle = 40 # approx mm - imu = adafruit_bno055.BNO055_I2C(i2c0) -imu.mode = adafruit_bno055.NDOF_MODE # should be in chapter 12! def stop(): motor_A1.duty_cycle = 0 diff --git a/ch-13/full-version/computer/robot_ble_connection.py b/ch-13/full-version/robot_ble_connection.py similarity index 92% rename from ch-13/full-version/computer/robot_ble_connection.py rename to ch-13/full-version/robot_ble_connection.py index 66dd100..59953bd 100644 --- a/ch-13/full-version/computer/robot_ble_connection.py +++ b/ch-13/full-version/robot_ble_connection.py @@ -19,7 +19,9 @@ class BleConnection: async def connect(self): print("Scanning for devices...") - devices = await bleak.BleakScanner.discover(service_uuids=[self.ble_uuid]) + devices = await bleak.BleakScanner.discover( + service_uuids=[self.ble_uuid] + ) print(f"Found {len(devices)} devices") print([device.name for device in devices]) ble_device_info = [device for device in devices if device.name==self.ble_name][0]