From da4966d8733dbd60576ce530d9ce609da26de3e0 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 19 Nov 2025 22:42:18 +0100 Subject: [PATCH 01/26] move docs over --- .github/PULL_REQUEST_TEMPLATE.md | 18 ++++++ .github/workflows/publish.yml | 44 +++++++++++++++ docs/contributing.md | 85 +++++++++++++++++++++++++++++ docs/generate_reference.py | 83 ++++++++++++++++++++++++++++ docs/getting_started.md | 75 +++++++++++++++++++++++++ docs/index.md | 18 ++++++ docs/stylesheets/extra.css | 22 ++++++++ docs/troubleshooting.md | 51 +++++++++++++++++ docs/tutorials/docker_management.md | 5 ++ docs/tutorials/field_creation.md | 3 + docs/tutorials/imu_calibration.md | 39 +++++++++++++ docs/tutorials/tutorials.md | 7 +++ mkdocs.yml | 56 +++++++++++++++++++ mkdocs_requirements.txt | 12 ++++ update_docs.sh | 10 ++++ 15 files changed, 528 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/publish.yml create mode 100644 docs/contributing.md create mode 100644 docs/generate_reference.py create mode 100644 docs/getting_started.md create mode 100644 docs/index.md create mode 100644 docs/stylesheets/extra.css create mode 100644 docs/troubleshooting.md create mode 100644 docs/tutorials/docker_management.md create mode 100644 docs/tutorials/field_creation.md create mode 100644 docs/tutorials/imu_calibration.md create mode 100644 docs/tutorials/tutorials.md create mode 100644 mkdocs.yml create mode 100644 mkdocs_requirements.txt create mode 100644 update_docs.sh diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..f8049bd --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ +### Motivation + + + + +### Implementation + + + + +### Progress + +- [ ] I chose a meaningful title that completes the sentence: "If applied, this PR will..." +- [ ] I chose meaningful labels (if GitHub allows me to so). +- [ ] The implementation is complete. +- [ ] Tests with a real hardware have been successful (or are not necessary). +- [ ] Pytests have been added (or are not necessary). +- [ ] Documentation has been added (or is not necessary). diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..fc1fcc8 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,44 @@ +name: Publish release + +on: + workflow_dispatch: + push: + tags: + - v** + +jobs: + docs: + name: Build and publish docs + runs-on: ubuntu-latest + needs: pypi + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + - name: Install dependencies + run: | + python3 -m pip install -r mkdocs_requirements.txt + python3 -m pip install -e . + - name: Build docs + run: mkdocs build -v + - name: Deploy gh-pages + uses: JamesIves/github-pages-deploy-action@v4.7.3 + with: + folder: site + # TODO: restructure in another PR + # - name: set version + # run: | + # VERSION=${{ env.VERSION }} + # - name: Create GitHub release entry + # uses: softprops/action-gh-release@v2 + # id: create_release + # with: + # draft: false + # prerelease: false + # name: ${{ env.VERSION }} + # tag_name: ${{ env.VERSION }} + # env: + # GITHUB_TOKEN: ${{ github.token }} diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..5cde196 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,85 @@ +# Contributing + +We're thrilled that you're interested in contributing to the Field Friend source code! +Here are some guidelines that will help you get started. + +## Reporting issues + +If you encounter a bug or other issue, the best way to report it is by opening a new issue on our [GitHub repository](https://github.com/zauberzeug/feldfreund). +When creating the issue, please provide a clear and concise description of the problem, including any relevant error messages and code snippets. +If possible, include steps to reproduce the issue. + +## Code of Conduct + +We follow a [Code of Conduct](https://github.com/zauberzeug/feldfreund/blob/main/CODE_OF_CONDUCT.md) to ensure that everyone who participates in the NiceGUI community feels welcome and safe. +By participating, you agree to abide by its terms. + +## Contributing code + +We are excited that you want to contribute code to the Field Friend source code. +We're always looking for bug fixes, performance improvements, and new features. + +## Coding Style Guide + +### Formatting + +We use [autopep8](https://github.com/hhatto/autopep8) with a 120 character line length to format our code. +Before submitting a pull request, please run + +```bash +autopep8 --max-line-length=120 --in-place --recursive . +``` + +on your code to ensure that it meets our formatting guidelines. +Alternatively you can use VSCode, open the feldfreund.code-workspace file and install the recommended extensions. +Then the formatting rules are applied whenever you save a file. + +In our point of view, the Black formatter is sometimes a bit too strict. +There are cases where one or the other arrangement of, e.g., function arguments is more readable than the other. +Then we like the flexibility to either put all arguments on separate lines or only put the lengthy event handler +on a second line and leave the other arguments as they are. + +### Imports + +We use [ruff](https://docs.astral.sh/ruff/) to automatically sort imports: + +```bash +ruff check . --fix +``` + +### Single vs Double Quotes + +Regarding single or double quotes: [PEP 8](https://peps.python.org/pep-0008/) doesn't give any recommendation, so we simply chose single quotes and sticked with it. +On qwerty keyboards it's a bit easier to type, is visually less cluttered, and it works well for strings containing double quotes from the English language. + +### F-Strings + +We use f-strings where ever possible because they are generally more readable - once you get used to them. +There are only a few places in the code base where performance really matters and f-strings might not be the best choice. +These places should be marked with a `# NOTE: ...` comment when diverging from f-string usage. + +## Documentation + +### Formatting + +Because it has [numerous benefits](https://nick.groenen.me/notes/one-sentence-per-line/) we write each sentence in a new line. + +### Examples + +Each example should be about one concept. +Please try to make them as minimal as possible to show what is needed to get some kind of functionality. +We are happy to merge pull requests with new examples which show new concepts, ideas or interesting use cases. + +## Pull requests + +To get started, fork the repository on GitHub, clone it somewhere on your filesystem, commit and push your changes, +and then open a pull request (PR) with a detailed description of the changes you've made +(the PR button is shown on the GitHub website of your forked repository). + +When submitting a PR, please make sure that the code follows the existing coding style and that all tests are passing. +If you're adding a new feature, please include tests that cover the new functionality. + +## Thank you! + +Thank you for your interest in contributing. +We're looking forward to work with you! diff --git a/docs/generate_reference.py b/docs/generate_reference.py new file mode 100644 index 0000000..b7797b6 --- /dev/null +++ b/docs/generate_reference.py @@ -0,0 +1,83 @@ +import dataclasses +import importlib +import inspect +import logging +from pathlib import Path +from types import ModuleType + +import mkdocs_gen_files + +nav = mkdocs_gen_files.Nav() + +logging.basicConfig(level=logging.DEBUG) + + +def extract_events(filepath: str) -> dict[str, str]: + with open(filepath, encoding='utf-8') as f: + lines = f.read().splitlines() + events = {} + for i, line in enumerate(lines): + if line.endswith('= Event()'): + event_name = line.strip().split()[0].removeprefix('self.') + event_doc = lines[i + 1].split('"""')[1] + events[event_name] = event_doc + return events + + +for path in sorted(Path('.').rglob('__init__.py')): + identifier = str(path.parent).replace('/', '.') + + if 'feldfreund_devkit' not in identifier: + continue + if identifier in ['feldfreund_devkit',]: + continue + + try: + module = importlib.import_module(identifier) + except Exception: + logging.warning('Failed to import %s', identifier) + continue + + doc_path = path.parent.with_suffix('.md') + found_something = False + for name in getattr(module, '__all__', dir(module)): + if name.startswith('_'): + logging.debug('skipping %s.%s: private', identifier, name) + continue + cls = getattr(module, name) + if isinstance(cls, ModuleType): + logging.debug('skipping %s.%s: sub-module', identifier, name) + continue + if dataclasses.is_dataclass(cls): + logging.debug('skipping %s.%s: dataclass', identifier, name) + continue + if not cls.__doc__: + logging.debug('skipping %s.%s: no docstring', identifier, name) + continue + + try: + events = extract_events(inspect.getfile(cls)) + except Exception: + logging.warning('skipping %s.%s: events', identifier, name) + continue + + with mkdocs_gen_files.open(Path('reference', doc_path), 'a') as fd: + print(f'::: {identifier}.{name}', file=fd) + if events: + print(' options:', file=fd) + print(' filters:', file=fd) + for event_name in events: + print(f' - "!{event_name}"', file=fd) + print('### Events', file=fd) + print('Name | Description', file=fd) + print('- | -', file=fd) + for event_name, event_doc in events.items(): + print(f'{event_name} | {event_doc}', file=fd) + print('', file=fd) + found_something = True + + if found_something: + nav[path.parent.parts[1:]] = doc_path.as_posix() + +with mkdocs_gen_files.open('reference/SUMMARY.md', 'w') as nav_file: + nav_file.writelines(nav.build_literate_nav()) diff --git a/docs/getting_started.md b/docs/getting_started.md new file mode 100644 index 0000000..fda8f4e --- /dev/null +++ b/docs/getting_started.md @@ -0,0 +1,75 @@ +# Getting Started + +## Run in Simulation + +We suggest you begin with simulating the Field Friend on your local development machine. +The software is meant to run on Linux and Unix systems so if you are using Windows, consider running in a Docker container or virtual machine. + +The Field Friend requires either Linux or Mac system with Python {{ python_version }} to run.
Windows is currently not supported, but may work by using Docker or a virtual machine. + +1. Clone the repository
`git clone git@github.com:zauberzeug/feldfreund.git && cd feldfreund` + +2. Create a file with your environment variables and replace `U4` with the name of your robot
`echo "ROBOT_ID=U4" > .env` + +Now you have two options, either you run the code in Docker, like it does on the robot, or you setup your local python environment to run it. +Should you face any problems during the setup, please check the [troubleshooting page](troubleshooting.md) or submit a [GitHub issue](https://github.com/zauberzeug/feldfreund/issues). + +### Docker Setup (recommended) + +1. Install [Docker](https://docs.docker.com/get-started/get-docker/) + +2. Build and start the container.
`./docker.sh U`
Our `docker.sh` script will automatically use the correct settings for your system. + +### Local Setup + +1. Optional: Setup a virtual environment with [venv](https://docs.python.org/3/library/venv.html)
`python3 -m venv .venv && source .venv/bin/activate` + +2. Install the python requirements
`python3 -m pip install -r requirements-dev.txt` + +3. Now you can run the program
`python3 main.py` + +In both cases, this will open the user interface of a simulated robot in your browser (if not browse to [http://localhost/](http://localhost/)). +The simulation will automatically hot reload upon code changes. +The Field Friend code is based on [RoSys](https://rosys.io) which itself uses [NiceGUI](https://nicegui.io), +both having a very gentle learning curve and are designed to boost your rapid development and testing. + +## Run on Real Hardware + +The following instructions will only work if you have a real Zauberzeug Field Friend at your disposal. +Contact [sales@zauberzeug.com](mailto:sales@zauberzeug.com) if you are interested in purchasing this robot. + +### Setup + +1. Ensure you can login via ssh without providing a password (via `ssh-copy-id` command) +2. Ensure you have [LiveSync](https://github.com/zauberzeug/livesync) installed with
`python3 -m pip install livesync` +3. Ensure the latest version of the docker image is installed on the Field Friend by syncing the code as described below and then running
`./docker.sh U` +4. Optional: ensure the correct docker containers are loaded on startup by running
`./docker.sh stopall && ./docker.sh U && ./docker.sh install` + + + +### Deploy and Change Code + +1. Go to your local `feldfreund` folder and start the [LiveSync](https://github.com/zauberzeug/livesync) script:
+ `./sync.py ` +2. This will deploy your local code to the Field Friend +3. As long as [LiveSync](https://github.com/zauberzeug/livesync) is active, all code change are automatically pushed to the machine +4. Any code changes will automatically trigger a hot reload on the Field Friend. + +### Update RoSys and NiceGUI + +To utilize personal versions of RoSys and NiceGUI instead of the default ones provided in the docker image, +modify the `sync.py` file by uncommenting the specific folders. + +### Logs + +You can see the current log with + +```bash +./docker.sh l rosys +``` + +The history of logs can be seen with + +```bash +less -r ~/.rosys/debug.log +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..2c5a178 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,18 @@ +# About + +**Zauberzeug Field Friend** is an autonomous, mobile, and AI-driven agricultural robot developed by [Zauberzeug GmbH](https://zauberzeug.com). +The robot is specifically designed for autonomous actions, combining lightness, flexibility, and robustness +to efficiently handle a variety of outdoor tasks. +Equipped with advanced sensor technologies and camera systems, +the Field Friend can precisely determine its position, follow crop lines and detect various kinds of plants. +With it's modular design, the Field Friend can be extended with various tools and sensors to fit the specific needs of the use case. + +## Features + +- The Open Source software encourages you to modify and enhance the behavior and adapt it to your specific needs. +- The Modular Design allows equipping with tools from Zauberzeug as well as third-party solutions or your own developments. +- Advanced Sensing and Autonomy-Algorithms allows autonomous navigation and obstacle avoidance. +- Full control via web interface remote and locally via WiFi. +- Manual steering with touch-joystick and keyboard or App. +- A combined camera/motor calibration for real world coordinate system (unit: meters) +- ... diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css new file mode 100644 index 0000000..6d595d7 --- /dev/null +++ b/docs/stylesheets/extra.css @@ -0,0 +1,22 @@ +:root { + --md-primary-fg-color: #6e93d6; + --md-default-fg-color: #3a3e42; + --md-accent-fg-color: #53b689; +} + +:root > * { + --md-code-hl-color: #d8e5fa; +} + +h2.doc-heading { + border-bottom: 1pt solid lightgray; +} + +img { + width: 70%; + display: block; + margin-left: auto; + margin-right: auto; + border-radius: 5px; + box-shadow: rgba(0, 0, 0, 0.25) 0 5px 10px; +} diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..8104792 --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,51 @@ +# Troubleshooting + +This section provides guidance for diagnosing and resolving issues during operation. Begin by checking the robot’s logs for warnings or errors. + +Live logs can be viewed using `docker.sh l rosys`, and archived logs are stored on the robot inside the `~/.rosys` directory. If further detail is required, enable debug-level logging on the [RoSys Logging Page](https://rosys.io/reference/rosys/analysis/#rosys.analysis.logging_page.LoggingPage) that is available at [/logging](http://localhost/logging). + +## Asyncio Warning + +While running RoSys you may see warnings similar to this one: + +``` +2021-10-31 15:08:04.040 [WARNING] asyncio: Executing wait_for=<_GatheringFuture pending cb=[()] created at /usr/local/lib/python3.9/asyncio/tasks.py:705> created at /usr/local/lib/python3.9/site-packages/justpy/justpy.py:261> took 0.238 seconds +``` + +This means some coroutine is clogging the event loop for too long. +In the above example it is a whopping 238 ms in which no other actor can do anything. +This is an eternity when machine communication is expected to happen about every 10 ms. +The warning also provides a (not so readable) hint where the time is consumed. + +The example above is one of the more frequent scenarios. +It means some code inside a user interaction event handler (e.g. `handle_event()` in `justpy.py`) is blocking. +Try to figure out which UI event code is responsible by commenting out parts of your logic and try to reproduce the warning systematically. + +## CairoSVG on Mac + +If [CairoSVG](https://cairosvg.org/) was installed via [Homebrew](https://brew.sh/), python sometimes can't find the correct path to run CairoSVG. +This will create a symbolic link to make the library accessible. + +```bash +sudo mkdir -p /usr/local/lib && sudo ln -sf /opt/homebrew/lib/libcairo.2.dylib /usr/local/lib/libcairo.2.dylib +``` + +You can test it with this command: + +```python +python3 -c "import cairocffi; import cairosvg; print('Cairo packages successfully imported!')" +``` + +## Missing Linux dependencies when running locally + +In case your Linux system is missing dependencies, look at the first lines of the provided [Dockerfile](https://github.com/zauberzeug/feldfreund/blob/main/Dockerfile) to find them. + +## Permission denied directly after startup + +If you get the `[Errno 13] Permission denied` error message right after you started `main.py`, your system is probably blocking the default port 80. +Try setting a custom port in your `.env`-file, like this + +``` +ROBOT_ID=U4 +PORT=8080 +``` diff --git a/docs/tutorials/docker_management.md b/docs/tutorials/docker_management.md new file mode 100644 index 0000000..bca0a45 --- /dev/null +++ b/docs/tutorials/docker_management.md @@ -0,0 +1,5 @@ +# docker.sh + +Here at Zauberzeug we deploy our software with Docker and to make it more intuitive, we provide a convenient shell script called `docker.sh` that simplifies common Docker operations. + +TODO diff --git a/docs/tutorials/field_creation.md b/docs/tutorials/field_creation.md new file mode 100644 index 0000000..0025b9c --- /dev/null +++ b/docs/tutorials/field_creation.md @@ -0,0 +1,3 @@ +# field creation + +TODO diff --git a/docs/tutorials/imu_calibration.md b/docs/tutorials/imu_calibration.md new file mode 100644 index 0000000..8cf5e95 --- /dev/null +++ b/docs/tutorials/imu_calibration.md @@ -0,0 +1,39 @@ +# Imu Calibration + +The IMU is not installed in its intended orientation, that is why we have to find the correct values. +The standard coordinate frame of our robots is a right-handed one where X is forward, Y is left and Z is upward. +The built-in IMUs orientation is X-left, Y-down and Z-backward, therefore a roll rotation of -90° and a yaw rotation of 90° is needed for a Robot Brain in its default configuration, where the socket connectors show backwards. +Older robots like U4 will need an additional yaw rotation of 90° afterwards, because their Robot Brains are built in sideways. + +Here is a short Python script to generate the needed configuration: + +```python +#!/usr/bin/env python3 +import numpy as np +from rosys.geometry import Rotation + +base_rotation = Rotation.from_euler(np.deg2rad(-90), 0, np.deg2rad(90)) +print(f'{base_rotation=}') + +roll = np.deg2rad(0.0) +pitch = np.deg2rad(0.0) +correction = Rotation.from_euler(roll, pitch, 0.0) +print(f'{correction=}') + +complete_correction = correction * base_rotation +print(f'{complete_correction=}') + +print('\nCode snippet for your robot\'s configuration:') +print(f'imu=Imu(offset_rotation=Rotation.from_euler({complete_correction.roll:.6f}, {complete_correction.pitch:.6f}, {complete_correction.yaw:.6f}))') +``` + +Steps: + +1. Find the correct base orientation of your IMU. + If your Field Friend has the standard configuration, you can use this as a starting point: + `Imu(offset_rotation=Rotation.from_euler(-1.570796, -0.000000, 1.570796))` +2. Roll and pitch your robot manually to check if the configuration is correct and the axes are correctly rotated. +3. Place your robot on a level surface and check the IMU's current values on the [development page](http://192.168.42.2/dev) +4. Put the shown values for roll and pitch in the script above. + That will generate your final configuration values. + Note, that IMU values have some noise, so your configuration won't be perfect. diff --git a/docs/tutorials/tutorials.md b/docs/tutorials/tutorials.md new file mode 100644 index 0000000..6ee22ae --- /dev/null +++ b/docs/tutorials/tutorials.md @@ -0,0 +1,7 @@ +# Tutorials + +Welcome to the Field Friend tutorials section! Here you'll find step-by-step guides to help you get the most out of your Field Friend robot. + +- [Docker Management](docker_management.md) - Learn how to use the docker.sh script to manage your Field Friend containers +- [Field Creation](field_creation.md) - Guide to creating and configuring fields for your robot +- [IMU calibration](imu_calibration.md) - How to determine the correct rotation for the ImuConfiguration diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..600cfae --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,56 @@ +site_name: Feldfreund Devkit Software Documentation +site_url: https://docs.feldfreund.de/ +nav: + - index.md + - getting_started.md + - Tutorials: + - tutorials/tutorials.md + - tutorials/docker_management.md + - tutorials/field_creation.md + - Module Reference: reference/ + - contributing.md + - troubleshooting.md +repo_url: https://github.com/zauberzeug/feldfreund_devkit +edit_uri: edit/main/docs/ +theme: + name: material + font: + text: Source Sans Pro + features: + - content.code.annotate +extra_css: + - stylesheets/extra.css +markdown_extensions: + - toc: + permalink: True + - admonition + - def_list + - mdx_include: + base_path: docs + - pymdownx.highlight + - pymdownx.inlinehilite + - pymdownx.superfences + - pymdownx.snippets + - attr_list + - footnotes +plugins: + - search + - gen-files: + scripts: + - docs/generate_reference.py + - literate-nav: + nav_file: SUMMARY.md + - section-index + - mkdocstrings: + default_handler: python + handlers: + python: + options: + show_root_heading: true + show_root_full_path: false + show_source: false + show_signature_annotations: true + merge_init_into_class: true + separate_signature: true +watch: + - feldfreund_devkit diff --git a/mkdocs_requirements.txt b/mkdocs_requirements.txt new file mode 100644 index 0000000..f724c1b --- /dev/null +++ b/mkdocs_requirements.txt @@ -0,0 +1,12 @@ +black +mdx-footnotes2 +mdx-include +mkdocs==1.5.3 +mkdocs-gen-files +mkdocs-literate-nav +mkdocs-macros-plugin +mkdocs-material +mkdocs-pymdownx-material-extras +mkdocs-section-index +mkdocstrings-python +toml diff --git a/update_docs.sh b/update_docs.sh new file mode 100644 index 0000000..0885492 --- /dev/null +++ b/update_docs.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# Script to update documentation with information from pyproject.toml + +# Install required packages if not already installed +pip install -r docs_requirements.txt + +# Run the update script +python update_docs.py + +echo "Documentation update complete!" From 3748b2f1f020a0aa0a41ea34f42b9f55a84c74d0 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 17 Dec 2025 23:02:22 +0100 Subject: [PATCH 02/26] add image --- assets/feldfreund.webp | Bin 0 -> 195156 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/feldfreund.webp diff --git a/assets/feldfreund.webp b/assets/feldfreund.webp new file mode 100644 index 0000000000000000000000000000000000000000..e056b44fea3a8f30620df0a6b8d97e82646496a0 GIT binary patch literal 195156 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 AH~;_u literal 0 HcmV?d00001 From ea10a5a07718b48207871c4bc6d0596424815837 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 17 Dec 2025 23:02:31 +0100 Subject: [PATCH 03/26] update README --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2e54cc2..f16c67f 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,15 @@ +Feldfreund rendering + # Feldfreund DevKit -TODO +This is the source code of the [Feldfreund Dev Kit](https://zauberzeug.com/products/field-friend-dev-kit) for autonomous outdoor robotics made by [Zauberzeug](https://zauberzeug.com/). +The software is based on [RoSys](https://rosys.io) and [NiceGUI](https://nicegui.io/). +The micro controller is programmed with [Lizard](https://github.com/zauberzeug/lizard). -## Tech Stack +Our agricultural weeding robot [Feldfreund](https://zauberzeug.com/feldfreund) is based on this platform and is intended to advance organic and regenerative agriculture. +There is also a [ROS2 implementation](https://github.com/zauberzeug/feldfreund_devkit_ros) based on this repository. -- Python 3.11+ -- [NiceGUI](https://nicegui.io) for web interface -- [Poetry](https://python-poetry.org) for dependency management -- [RoSys](https://rosys.io) framework -- [Copier](https://copier.readthedocs.io/) for template configuration (from [nicegui-template](https://github.com/zauberzeug/nicegui-template)) +Please see the [documentation](https://docs.feldfreund.de) for details on installation, setup and usage. ## Development From 69f25be64caaa163eb96c518b600c39ba1585ff5 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Thu, 18 Dec 2025 00:25:24 +0100 Subject: [PATCH 04/26] update docs --- docs/generate_reference.py | 53 +++++++------------ docs/tutorials/docker_management.md | 5 -- docs/tutorials/field_creation.md | 3 -- docs/tutorials/odrive_calibration.md | 52 ++++++++++++++++++ docs/tutorials/tutorials.md | 3 +- .../navigation/waypoint_navigation.py | 10 ++-- mkdocs.yml | 10 ++-- odrive/README.md | 44 --------------- 8 files changed, 86 insertions(+), 94 deletions(-) delete mode 100644 docs/tutorials/docker_management.md delete mode 100644 docs/tutorials/field_creation.md create mode 100644 docs/tutorials/odrive_calibration.md delete mode 100644 odrive/README.md diff --git a/docs/generate_reference.py b/docs/generate_reference.py index b7797b6..b1d5bb5 100644 --- a/docs/generate_reference.py +++ b/docs/generate_reference.py @@ -2,6 +2,8 @@ import importlib import inspect import logging +import re +import sys from pathlib import Path from types import ModuleType @@ -9,65 +11,50 @@ nav = mkdocs_gen_files.Nav() -logging.basicConfig(level=logging.DEBUG) - def extract_events(filepath: str) -> dict[str, str]: with open(filepath, encoding='utf-8') as f: lines = f.read().splitlines() - events = {} + events_: dict[str, str] = {} for i, line in enumerate(lines): - if line.endswith('= Event()'): - event_name = line.strip().split()[0].removeprefix('self.') - event_doc = lines[i + 1].split('"""')[1] - events[event_name] = event_doc - return events + if re.search(r'= Event(\[.*?\])?\(\)$', line): + event_name_ = line.strip().split()[0].removeprefix('self.') + event_doc_ = lines[i+1].split('"""')[1] + events_[event_name_] = event_doc_ + return events_ for path in sorted(Path('.').rglob('__init__.py')): identifier = str(path.parent).replace('/', '.') - - if 'feldfreund_devkit' not in identifier: - continue if identifier in ['feldfreund_devkit',]: continue - try: module = importlib.import_module(identifier) except Exception: - logging.warning('Failed to import %s', identifier) - continue + logging.exception('Failed to import %s', identifier) + sys.exit(1) doc_path = path.parent.with_suffix('.md') found_something = False for name in getattr(module, '__all__', dir(module)): if name.startswith('_'): - logging.debug('skipping %s.%s: private', identifier, name) - continue + continue # skip private fields cls = getattr(module, name) if isinstance(cls, ModuleType): - logging.debug('skipping %s.%s: sub-module', identifier, name) - continue + continue # skip sub-modules if dataclasses.is_dataclass(cls): - logging.debug('skipping %s.%s: dataclass', identifier, name) - continue + continue # skip dataclasses if not cls.__doc__: - logging.debug('skipping %s.%s: no docstring', identifier, name) - continue - - try: - events = extract_events(inspect.getfile(cls)) - except Exception: - logging.warning('skipping %s.%s: events', identifier, name) - continue - + continue # skip classes without docstring + events = extract_events(inspect.getfile(cls)) with mkdocs_gen_files.open(Path('reference', doc_path), 'a') as fd: print(f'::: {identifier}.{name}', file=fd) + print(' options:', file=fd) + print(' filters:', file=fd) + print(' - "!^_[^_]"', file=fd) + for event_name in events: + print(f' - "!{event_name}"', file=fd) if events: - print(' options:', file=fd) - print(' filters:', file=fd) - for event_name in events: - print(f' - "!{event_name}"', file=fd) print('### Events', file=fd) print('Name | Description', file=fd) print('- | -', file=fd) diff --git a/docs/tutorials/docker_management.md b/docs/tutorials/docker_management.md deleted file mode 100644 index bca0a45..0000000 --- a/docs/tutorials/docker_management.md +++ /dev/null @@ -1,5 +0,0 @@ -# docker.sh - -Here at Zauberzeug we deploy our software with Docker and to make it more intuitive, we provide a convenient shell script called `docker.sh` that simplifies common Docker operations. - -TODO diff --git a/docs/tutorials/field_creation.md b/docs/tutorials/field_creation.md deleted file mode 100644 index 0025b9c..0000000 --- a/docs/tutorials/field_creation.md +++ /dev/null @@ -1,3 +0,0 @@ -# field creation - -TODO diff --git a/docs/tutorials/odrive_calibration.md b/docs/tutorials/odrive_calibration.md new file mode 100644 index 0000000..a883f19 --- /dev/null +++ b/docs/tutorials/odrive_calibration.md @@ -0,0 +1,52 @@ +# ODrive Calibration + +## Flashing ODrive + +To flash an ODrive it has to be put into DFU Mode. +For this there is a switch on the black ODrive board. +This switch has to be put into the DFU setting. +Following this, the whole board needs to be power cycled (Including RdyP and the battery connection). +Then the ODrive needs to be connected to the Robot Brain using a micro-USB cable. + +Now, from the odrive directory, the following command can be run. +This will flash the STM chip with the newest firmware. + +```bash +./flash_odrive.sh fw-v5.6-feldfreund/ODriveFirmware.bin +``` + +## Calibrating ODrive + +To calibrate the ODrives, they have to be in the run mode(switch with DFU and run). +The normal Feldfreund Lizard script will interfere with the calibration script. +In order to prevent this the `calibration.liz` needs to be configured. +This can be done in the `/lizard` folder with the command: + +```bash +./configure.py /calibration.liz +``` + +If this is failing, make sure there are no other serial connections running to the ESP. + +Before starting the calibration make sure, that the tracks do not touch the ground and the ODrive is connected to the Robot Brain using the micro-USB cable. +Then for the right track run: + +```bash +python3 calibrate_two_motors_r.py +``` + +and for the left track: + +```bash +python3 calibrate_two_motors_l.py +``` + +If the calibration does not work calling it with `sudo` can help. +These scripts will set the motor parameters and start the calibration of the hall sensors. +When you are done, don't forget to reconfigure the ESP with your Feldfreund code. + +## Further debugging + +Further debugging can be done using the `odrivetool`. +While the ODrive is connected via USB the tool can be started from the command line. +For further documentation reference the [ODrive documentation](https://docs.odriverobotics.com/v/0.5.6/getting-started.html). diff --git a/docs/tutorials/tutorials.md b/docs/tutorials/tutorials.md index 6ee22ae..97ea73b 100644 --- a/docs/tutorials/tutorials.md +++ b/docs/tutorials/tutorials.md @@ -2,6 +2,5 @@ Welcome to the Field Friend tutorials section! Here you'll find step-by-step guides to help you get the most out of your Field Friend robot. -- [Docker Management](docker_management.md) - Learn how to use the docker.sh script to manage your Field Friend containers -- [Field Creation](field_creation.md) - Guide to creating and configuring fields for your robot - [IMU calibration](imu_calibration.md) - How to determine the correct rotation for the ImuConfiguration +- [ODrive calibration](odrive_calibration.md) - Let the ODrive motor controllers calibrate themselves diff --git a/feldfreund_devkit/navigation/waypoint_navigation.py b/feldfreund_devkit/navigation/waypoint_navigation.py index 6a91c7f..9394dae 100644 --- a/feldfreund_devkit/navigation/waypoint_navigation.py +++ b/feldfreund_devkit/navigation/waypoint_navigation.py @@ -16,6 +16,8 @@ class WaypointNavigation(rosys.persistence.Persistable): + """Base class for all waypoint based navigation types.""" + LINEAR_SPEED_LIMIT: float = 0.13 def __init__(self, *, implement: Implement, driver: Driver, pose_provider: PoseProvider, name: str = 'Waypoint Navigation') -> None: @@ -29,7 +31,7 @@ def __init__(self, *, implement: Implement, driver: Driver, pose_provider: PoseP self.linear_speed_limit = self.LINEAR_SPEED_LIMIT self.PATH_GENERATED = Event[list[DriveSegment]]() - """a new path has been generated (argument: ``list[DriveSegment]``)""" + """a new path has been generated(argument: ``list[DriveSegment]``)""" self.SEGMENT_STARTED = Event[DriveSegment]() """a waypoint has been reached""" @@ -42,17 +44,19 @@ def __init__(self, *, implement: Implement, driver: Driver, pose_provider: PoseP @property def path(self) -> list[DriveSegment]: + """Returns the whole planned path.""" return self._upcoming_path @property def current_segment(self) -> DriveSegment | None: + """Returns the current segment to drive along or None if there are no waypoints left.""" if not self._upcoming_path: return None return self._upcoming_path[0] @property def has_waypoints(self) -> bool: - """Returns True as long as there are waypoints to drive to""" + """Returns True as long as there are waypoints to drive to.""" return self.current_segment is not None @track @@ -156,7 +160,7 @@ async def _block_until_implement_has_target(self) -> Point: def _remove_segments_behind_robot(self, path_segments: list[DriveSegment], *, completed_percentage: float = 0.99) -> list[DriveSegment]: - """Create new path (list of segments) starting at the closest segment to the current pose""" + """Create new path(list of segments) starting at the closest segment to the current pose""" current_pose = self.pose_provider.pose start_index = 0 for i, segment in enumerate(path_segments): diff --git a/mkdocs.yml b/mkdocs.yml index 600cfae..758fc57 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,13 +1,13 @@ -site_name: Feldfreund Devkit Software Documentation +site_name: Feldfreund Dev Kit Documentation site_url: https://docs.feldfreund.de/ nav: - index.md - getting_started.md - Tutorials: - tutorials/tutorials.md - - tutorials/docker_management.md - - tutorials/field_creation.md - - Module Reference: reference/ + - tutorials/imu_calibration.md + - tutorials/odrive_calibration.md + # - Module Reference: reference/ - contributing.md - troubleshooting.md repo_url: https://github.com/zauberzeug/feldfreund_devkit @@ -52,5 +52,7 @@ plugins: show_signature_annotations: true merge_init_into_class: true separate_signature: true + filters: + - "!^_[^_]" watch: - feldfreund_devkit diff --git a/odrive/README.md b/odrive/README.md deleted file mode 100644 index f6a36b5..0000000 --- a/odrive/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# ODrive Calibration - -## Flashing ODrive - -To flash an ODrive it has to be put into DFU Mode. For this there is a switch on the black ODrive board. This switch has to be put into the DFU setting. Following this, the whole board needs to be power cycled (Including RdyP and the battery connection). -Then the ODrive needs to be connected to the Robot Brain using a micro-USB cable. Now the command - -```bash -./flash_odrive.sh fw-v5.6-feldfreund/ODriveFirmware.bin -``` - -can be run. This will flash the STM chip with the newest firmware. - -## Calibrating ODirve - -To calibrate the ODrives, they have to be in the run mode(switch with DFU and run). The normal Feldfreund Lizard script will interfere with the calibration script. In order to prevent this the `calibration.liz` needs to be configured. This can be done in the `/lizard` folder with the command: - -```bash -./configure.py /calibration.liz -``` - -If this is failing, make sure there are no other serial connections running to the ESP. - -Before starting the calibration make sure, that the tracks do not touch the ground and the ODrive is connected to the Robot Brain using the micro-USB cable. Then for the right track run: - -```bash -python3 calibrate_two_motors_r.py -``` - -and for the left track: - -```bash -python3 calibrate_two_motors_l.py -``` - -If the calibration does not work calling it with `sudo` can help. - -These scripts will set the motor parameters and start the calibration of the hall sensors. - -When you are done, don't forget to reconfigure the ESP with your Feldfreund code. - -## Further debugging - -Further debugging can be done using the `odrivetool`. While the ODrive is connected via USB the tool can be started from the command line. For further documentation reference the [ODrive documentation](https://docs.odriverobotics.com/v/0.5.6/getting-started.html). From 0201fdcd26f29badb8ed32bf1ac8698ca67511d6 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 19:55:58 +0100 Subject: [PATCH 05/26] switch to uv --- .github/workflows/publish.yml | 10 +- mkdocs_requirements.txt | 12 - pyproject.toml | 15 ++ uv.lock | 492 +++++++++++++++++++++++++++++++++- 4 files changed, 503 insertions(+), 26 deletions(-) delete mode 100644 mkdocs_requirements.txt diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index fc1fcc8..35ee05d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,14 +14,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.13" + - name: Install uv + uses: astral-sh/setup-uv@v5 - name: Install dependencies - run: | - python3 -m pip install -r mkdocs_requirements.txt - python3 -m pip install -e . + run: uv sync --group docs - name: Build docs run: mkdocs build -v - name: Deploy gh-pages diff --git a/mkdocs_requirements.txt b/mkdocs_requirements.txt deleted file mode 100644 index f724c1b..0000000 --- a/mkdocs_requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -black -mdx-footnotes2 -mdx-include -mkdocs==1.5.3 -mkdocs-gen-files -mkdocs-literate-nav -mkdocs-macros-plugin -mkdocs-material -mkdocs-pymdownx-material-extras -mkdocs-section-index -mkdocstrings-python -toml diff --git a/pyproject.toml b/pyproject.toml index 1e367fb..66902e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,21 @@ test = [ types = [ "types-psutil>=7.1.3.20251211", ] +docs = [ + "black", + "click (<8.3.0)", + "mdx-footnotes2", + "mdx-include", + "mkdocs (>=1.6.1)", + "mkdocs-gen-files", + "mkdocs-literate-nav", + "mkdocs-macros-plugin", + "mkdocs-material", + "mkdocs-pymdownx-material-extras", + "mkdocs-section-index", + "mkdocstrings-python", + "toml", +] [build-system] requires = [ diff --git a/uv.lock b/uv.lock index c2c10c1..0c8c58d 100644 --- a/uv.lock +++ b/uv.lock @@ -173,6 +173,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl", hash = "sha256:ce8ad498672c845a0c3de2629c15b635ec2b05ef8177a6e7c91c74f3e9b51128", size = 45807, upload-time = "2025-01-14T14:46:15.466Z" }, ] +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + +[[package]] +name = "backrefs" +version = "6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/86/e3/bb3a439d5cb255c4774724810ad8073830fac9c9dee123555820c1bcc806/backrefs-6.1.tar.gz", hash = "sha256:3bba1749aafe1db9b915f00e0dd166cba613b6f788ffd63060ac3485dc9be231", size = 7011962, upload-time = "2025-11-15T14:52:08.323Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ee/c216d52f58ea75b5e1841022bbae24438b19834a29b163cb32aa3a2a7c6e/backrefs-6.1-py310-none-any.whl", hash = "sha256:2a2ccb96302337ce61ee4717ceacfbf26ba4efb1d55af86564b8bbaeda39cac1", size = 381059, upload-time = "2025-11-15T14:51:59.758Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9a/8da246d988ded941da96c7ed945d63e94a445637eaad985a0ed88787cb89/backrefs-6.1-py311-none-any.whl", hash = "sha256:e82bba3875ee4430f4de4b6db19429a27275d95a5f3773c57e9e18abc23fd2b7", size = 392854, upload-time = "2025-11-15T14:52:01.194Z" }, + { url = "https://files.pythonhosted.org/packages/37/c9/fd117a6f9300c62bbc33bc337fd2b3c6bfe28b6e9701de336b52d7a797ad/backrefs-6.1-py312-none-any.whl", hash = "sha256:c64698c8d2269343d88947c0735cb4b78745bd3ba590e10313fbf3f78c34da5a", size = 398770, upload-time = "2025-11-15T14:52:02.584Z" }, + { url = "https://files.pythonhosted.org/packages/eb/95/7118e935b0b0bd3f94dfec2d852fd4e4f4f9757bdb49850519acd245cd3a/backrefs-6.1-py313-none-any.whl", hash = "sha256:4c9d3dc1e2e558965202c012304f33d4e0e477e1c103663fd2c3cc9bb18b0d05", size = 400726, upload-time = "2025-11-15T14:52:04.093Z" }, + { url = "https://files.pythonhosted.org/packages/02/e3/a4fa1946722c4c7b063cc25043a12d9ce9b4323777f89643be74cef2993c/backrefs-6.1-py39-none-any.whl", hash = "sha256:a9e99b8a4867852cad177a6430e31b0f6e495d65f8c6c134b68c14c3c95bf4b0", size = 381058, upload-time = "2025-11-15T14:52:06.698Z" }, +] + [[package]] name = "bidict" version = "0.23.1" @@ -182,6 +204,38 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5", size = 32764, upload-time = "2024-02-18T19:09:04.156Z" }, ] +[[package]] +name = "black" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "pytokens" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/88/560b11e521c522440af991d46848a2bde64b5f7202ec14e1f46f9509d328/black-26.1.0.tar.gz", hash = "sha256:d294ac3340eef9c9eb5d29288e96dc719ff269a88e27b396340459dd85da4c58", size = 658785, upload-time = "2026-01-18T04:50:11.993Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/83/f05f22ff13756e1a8ce7891db517dbc06200796a16326258268f4658a745/black-26.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3cee1487a9e4c640dc7467aaa543d6c0097c391dc8ac74eb313f2fbf9d7a7cb5", size = 1831956, upload-time = "2026-01-18T04:59:21.38Z" }, + { url = "https://files.pythonhosted.org/packages/7d/f2/b2c570550e39bedc157715e43927360312d6dd677eed2cc149a802577491/black-26.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d62d14ca31c92adf561ebb2e5f2741bf8dea28aef6deb400d49cca011d186c68", size = 1672499, upload-time = "2026-01-18T04:59:23.257Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d7/990d6a94dc9e169f61374b1c3d4f4dd3037e93c2cc12b6f3b12bc663aa7b/black-26.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb1dafbbaa3b1ee8b4550a84425aac8874e5f390200f5502cf3aee4a2acb2f14", size = 1735431, upload-time = "2026-01-18T04:59:24.729Z" }, + { url = "https://files.pythonhosted.org/packages/36/1c/cbd7bae7dd3cb315dfe6eeca802bb56662cc92b89af272e014d98c1f2286/black-26.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:101540cb2a77c680f4f80e628ae98bd2bd8812fb9d72ade4f8995c5ff019e82c", size = 1400468, upload-time = "2026-01-18T04:59:27.381Z" }, + { url = "https://files.pythonhosted.org/packages/59/b1/9fe6132bb2d0d1f7094613320b56297a108ae19ecf3041d9678aec381b37/black-26.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:6f3977a16e347f1b115662be07daa93137259c711e526402aa444d7a88fdc9d4", size = 1207332, upload-time = "2026-01-18T04:59:28.711Z" }, + { url = "https://files.pythonhosted.org/packages/f5/13/710298938a61f0f54cdb4d1c0baeb672c01ff0358712eddaf29f76d32a0b/black-26.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6eeca41e70b5f5c84f2f913af857cf2ce17410847e1d54642e658e078da6544f", size = 1878189, upload-time = "2026-01-18T04:59:30.682Z" }, + { url = "https://files.pythonhosted.org/packages/79/a6/5179beaa57e5dbd2ec9f1c64016214057b4265647c62125aa6aeffb05392/black-26.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dd39eef053e58e60204f2cdf059e2442e2eb08f15989eefe259870f89614c8b6", size = 1700178, upload-time = "2026-01-18T04:59:32.387Z" }, + { url = "https://files.pythonhosted.org/packages/8c/04/c96f79d7b93e8f09d9298b333ca0d31cd9b2ee6c46c274fd0f531de9dc61/black-26.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9459ad0d6cd483eacad4c6566b0f8e42af5e8b583cee917d90ffaa3778420a0a", size = 1777029, upload-time = "2026-01-18T04:59:33.767Z" }, + { url = "https://files.pythonhosted.org/packages/49/f9/71c161c4c7aa18bdda3776b66ac2dc07aed62053c7c0ff8bbda8c2624fe2/black-26.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a19915ec61f3a8746e8b10adbac4a577c6ba9851fa4a9e9fbfbcf319887a5791", size = 1406466, upload-time = "2026-01-18T04:59:35.177Z" }, + { url = "https://files.pythonhosted.org/packages/4a/8b/a7b0f974e473b159d0ac1b6bcefffeb6bec465898a516ee5cc989503cbc7/black-26.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:643d27fb5facc167c0b1b59d0315f2674a6e950341aed0fc05cf307d22bf4954", size = 1216393, upload-time = "2026-01-18T04:59:37.18Z" }, + { url = "https://files.pythonhosted.org/packages/79/04/fa2f4784f7237279332aa735cdfd5ae2e7730db0072fb2041dadda9ae551/black-26.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ba1d768fbfb6930fc93b0ecc32a43d8861ded16f47a40f14afa9bb04ab93d304", size = 1877781, upload-time = "2026-01-18T04:59:39.054Z" }, + { url = "https://files.pythonhosted.org/packages/cf/ad/5a131b01acc0e5336740a039628c0ab69d60cf09a2c87a4ec49f5826acda/black-26.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2b807c240b64609cb0e80d2200a35b23c7df82259f80bef1b2c96eb422b4aac9", size = 1699670, upload-time = "2026-01-18T04:59:41.005Z" }, + { url = "https://files.pythonhosted.org/packages/da/7c/b05f22964316a52ab6b4265bcd52c0ad2c30d7ca6bd3d0637e438fc32d6e/black-26.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1de0f7d01cc894066a1153b738145b194414cc6eeaad8ef4397ac9abacf40f6b", size = 1775212, upload-time = "2026-01-18T04:59:42.545Z" }, + { url = "https://files.pythonhosted.org/packages/a6/a3/e8d1526bea0446e040193185353920a9506eab60a7d8beb062029129c7d2/black-26.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:91a68ae46bf07868963671e4d05611b179c2313301bd756a89ad4e3b3db2325b", size = 1409953, upload-time = "2026-01-18T04:59:44.357Z" }, + { url = "https://files.pythonhosted.org/packages/c7/5a/d62ebf4d8f5e3a1daa54adaab94c107b57be1b1a2f115a0249b41931e188/black-26.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:be5e2fe860b9bd9edbf676d5b60a9282994c03fbbd40fe8f5e75d194f96064ca", size = 1217707, upload-time = "2026-01-18T04:59:45.719Z" }, + { url = "https://files.pythonhosted.org/packages/e4/3d/51bdb3ecbfadfaf825ec0c75e1de6077422b4afa2091c6c9ba34fbfc0c2d/black-26.1.0-py3-none-any.whl", hash = "sha256:1054e8e47ebd686e078c0bb0eaf31e6ce69c966058d122f2c0c950311f9f3ede", size = 204010, upload-time = "2026-01-18T04:50:09.978Z" }, +] + [[package]] name = "cairocffi" version = "1.7.1" @@ -335,14 +389,14 @@ wheels = [ [[package]] name = "click" -version = "8.3.1" +version = "8.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, + { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, ] [[package]] @@ -448,6 +502,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, ] +[[package]] +name = "cyclic" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/9f/becc4fea44301f232e4eba17752001bd708e3c042fef37a72b9af7ddf4b5/cyclic-1.0.0.tar.gz", hash = "sha256:ecddd56cb831ee3e6b79f61ecb0ad71caee606c507136867782911aa01c3e5eb", size = 2167, upload-time = "2018-09-26T16:47:07.285Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/c0/9f59d2ebd9d585e1681c51767eb138bcd9d0ea770f6fc003cd875c7f5e62/cyclic-1.0.0-py3-none-any.whl", hash = "sha256:32d8181d7698f426bce6f14f4c3921ef95b6a84af9f96192b59beb05bc00c3ed", size = 2547, upload-time = "2018-09-26T16:47:05.609Z" }, +] + [[package]] name = "dataclasses-json" version = "0.5.14" @@ -546,6 +609,21 @@ dev = [ { name = "ruff" }, { name = "types-psutil" }, ] +docs = [ + { name = "black" }, + { name = "click" }, + { name = "mdx-footnotes2" }, + { name = "mdx-include" }, + { name = "mkdocs" }, + { name = "mkdocs-gen-files" }, + { name = "mkdocs-literate-nav" }, + { name = "mkdocs-macros-plugin" }, + { name = "mkdocs-material" }, + { name = "mkdocs-pymdownx-material-extras" }, + { name = "mkdocs-section-index" }, + { name = "mkdocstrings-python" }, + { name = "toml" }, +] test = [ { name = "pytest" }, { name = "pytest-asyncio" }, @@ -568,12 +646,27 @@ requires-dist = [ dev = [ { name = "autopep8", specifier = ">=2.3.2,<3.0.0" }, { name = "mypy", specifier = ">=1.18.2,<2.0.0" }, - { name = "poetry-dynamic-versioning", specifier = ">=1.8.0,<2" }, + { name = "poetry-dynamic-versioning", specifier = ">=1.8.0,<2.0.0" }, { name = "pre-commit", specifier = ">=4.3.0,<5.0.0" }, { name = "pylint", specifier = ">=3.3.3,<4.0.0" }, { name = "ruff", specifier = ">=0.13.2,<1.0.0" }, { name = "types-psutil", specifier = ">=7.1.3.20251211" }, ] +docs = [ + { name = "black" }, + { name = "click", specifier = "<8.3.0" }, + { name = "mdx-footnotes2" }, + { name = "mdx-include" }, + { name = "mkdocs", specifier = ">=1.6.1" }, + { name = "mkdocs-gen-files" }, + { name = "mkdocs-literate-nav" }, + { name = "mkdocs-macros-plugin" }, + { name = "mkdocs-material" }, + { name = "mkdocs-pymdownx-material-extras" }, + { name = "mkdocs-section-index" }, + { name = "mkdocstrings-python" }, + { name = "toml" }, +] test = [ { name = "pytest", specifier = ">=8.3.4,<9.0.0" }, { name = "pytest-asyncio", specifier = ">=1.2.0,<2.0.0" }, @@ -695,6 +788,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, ] +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + +[[package]] +name = "griffe" +version = "1.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0d/0c/3a471b6e31951dce2360477420d0a8d1e00dea6cf33b70f3e8c3ab6e28e1/griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea", size = 424112, upload-time = "2025-11-10T15:03:15.52Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl", hash = "sha256:6f6762661949411031f5fcda9593f586e6ce8340f0ba88921a0f2ef7a81eb9a3", size = 150705, upload-time = "2025-11-10T15:03:13.549Z" }, +] + [[package]] name = "h11" version = "0.16.0" @@ -704,6 +821,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] +[[package]] +name = "hjson" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/e5/0b56d723a76ca67abadbf7fb71609fb0ea7e6926e94fcca6c65a85b36a0e/hjson-3.1.0.tar.gz", hash = "sha256:55af475a27cf83a7969c808399d7bccdec8fb836a07ddbd574587593b9cdcf75", size = 40541, upload-time = "2022-08-13T02:53:01.919Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/7f/13cd798d180af4bf4c0ceddeefba2b864a63c71645abc0308b768d67bb81/hjson-3.1.0-py3-none-any.whl", hash = "sha256:65713cdcf13214fb554eb8b4ef803419733f4f5e551047c9b711098ab7186b89", size = 54018, upload-time = "2022-08-13T02:52:59.899Z" }, +] + [[package]] name = "httpcore" version = "1.0.9" @@ -1010,6 +1136,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/23/9c/ab8a94c30c082caca87bc0db78efe91372e45d35a700ef07ffe78ed10cda/line_profiler-4.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:727e970d358616a1a33d51d696efec932a5ef7730785df62658bd7e74aa58951", size = 128232, upload-time = "2024-12-03T17:11:51.741Z" }, ] +[[package]] +name = "markdown" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/7dd27d9d863b3376fcf23a5a13cb5d024aed1db46f963f1b5735ae43b3be/markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e", size = 364931, upload-time = "2025-11-03T19:51:15.007Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/81/54e3ce63502cd085a0c556652a4e1b919c45a446bd1e5300e10c44c8c521/markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c", size = 107678, upload-time = "2025-11-03T19:51:13.887Z" }, +] + [[package]] name = "markdown2" version = "2.5.4" @@ -1142,6 +1277,225 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" }, ] +[[package]] +name = "mdx-footnotes2" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/0b/bb28aef565b22becb5d0354232baae3a7b9d8d6af5e0f95b30a260539f98/mdx-footnotes2-0.3.0.tar.gz", hash = "sha256:a56210594f7aee3ee1956dc64acad4bb5bf317278d111323e638c89292b6927e", size = 6946, upload-time = "2021-04-09T07:55:13.772Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/35/fa5c6a0f9b67e0275ba69ea6b33b25e2140c1a916fc6b66059165dce1c7a/mdx_footnotes2-0.3.0-py3-none-any.whl", hash = "sha256:0d7179870c645027187d5ca4c24deba611912fe9d3e619ecd4804450a944d077", size = 7149, upload-time = "2021-04-09T07:55:12.439Z" }, +] + +[[package]] +name = "mdx-include" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cyclic" }, + { name = "markdown" }, + { name = "rcslice" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/f0/f395a9cf164471d3c7bbe58cbd64d74289575a8b85a962b49a804ab7ed34/mdx_include-1.4.2.tar.gz", hash = "sha256:992f9fbc492b5cf43f7d8cb4b90b52a4e4c5fdd7fd04570290a83eea5c84f297", size = 15051, upload-time = "2022-07-26T05:46:14.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/40/6844997dee251103c5a4c4eb0d1d2f2162b7c29ffc4e86de3cd68d269be2/mdx_include-1.4.2-py3-none-any.whl", hash = "sha256:cfbeadd59985f27a9b70cb7ab0a3d209892fe1bb1aa342df055e0b135b3c9f34", size = 11591, upload-time = "2022-07-26T05:46:11.518Z" }, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/fa/9124cd63d822e2bcbea1450ae68cdc3faf3655c69b455f3a7ed36ce6c628/mkdocs_autorefs-1.4.3.tar.gz", hash = "sha256:beee715b254455c4aa93b6ef3c67579c399ca092259cc41b7d9342573ff1fc75", size = 55425, upload-time = "2025-08-26T14:23:17.223Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/4d/7123b6fa2278000688ebd338e2a06d16870aaf9eceae6ba047ea05f92df1/mkdocs_autorefs-1.4.3-py3-none-any.whl", hash = "sha256:469d85eb3114801d08e9cc55d102b3ba65917a869b893403b8987b601cf55dc9", size = 25034, upload-time = "2025-08-26T14:23:15.906Z" }, +] + +[[package]] +name = "mkdocs-gen-files" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/35/f26349f7fa18414eb2e25d75a6fa9c7e3186c36e1d227c0b2d785a7bd5c4/mkdocs_gen_files-0.6.0.tar.gz", hash = "sha256:52022dc14dcc0451e05e54a8f5d5e7760351b6701eff816d1e9739577ec5635e", size = 8642, upload-time = "2025-11-23T12:13:22.124Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/ec/72417415563c60ae01b36f0d497f1f4c803972f447ef4fb7f7746d6e07db/mkdocs_gen_files-0.6.0-py3-none-any.whl", hash = "sha256:815af15f3e2dbfda379629c1b95c02c8e6f232edf2a901186ea3b204ab1135b2", size = 8182, upload-time = "2025-11-23T12:13:20.756Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" }, +] + +[[package]] +name = "mkdocs-literate-nav" +version = "0.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f6/5f/99aa379b305cd1c2084d42db3d26f6de0ea9bf2cc1d10ed17f61aff35b9a/mkdocs_literate_nav-0.6.2.tar.gz", hash = "sha256:760e1708aa4be86af81a2b56e82c739d5a8388a0eab1517ecfd8e5aa40810a75", size = 17419, upload-time = "2025-03-18T21:53:09.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/84/b5b14d2745e4dd1a90115186284e9ee1b4d0863104011ab46abb7355a1c3/mkdocs_literate_nav-0.6.2-py3-none-any.whl", hash = "sha256:0a6489a26ec7598477b56fa112056a5e3a6c15729f0214bea8a4dbc55bd5f630", size = 13261, upload-time = "2025-03-18T21:53:08.1Z" }, +] + +[[package]] +name = "mkdocs-macros-plugin" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "hjson" }, + { name = "jinja2" }, + { name = "mkdocs" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "python-dateutil" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "super-collections" }, + { name = "termcolor" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/92/15/e6a44839841ebc9c5872fa0e6fad1c3757424e4fe026093b68e9f386d136/mkdocs_macros_plugin-1.5.0.tar.gz", hash = "sha256:12aa45ce7ecb7a445c66b9f649f3dd05e9b92e8af6bc65e4acd91d26f878c01f", size = 37730, upload-time = "2025-11-13T08:08:55.545Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/62/9fffba5bb9ed3d31a932ad35038ba9483d59850256ee0fea7f1187173983/mkdocs_macros_plugin-1.5.0-py3-none-any.whl", hash = "sha256:c10fabd812bf50f9170609d0ed518e54f1f0e12c334ac29141723a83c881dd6f", size = 44626, upload-time = "2025-11-13T08:08:53.878Z" }, +] + +[[package]] +name = "mkdocs-material" +version = "9.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "backrefs" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/27/e2/2ffc356cd72f1473d07c7719d82a8f2cbd261666828614ecb95b12169f41/mkdocs_material-9.7.1.tar.gz", hash = "sha256:89601b8f2c3e6c6ee0a918cc3566cb201d40bf37c3cd3c2067e26fadb8cce2b8", size = 4094392, upload-time = "2025-12-18T09:49:00.308Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/32/ed071cb721aca8c227718cffcf7bd539620e9799bbf2619e90c757bfd030/mkdocs_material-9.7.1-py3-none-any.whl", hash = "sha256:3f6100937d7d731f87f1e3e3b021c97f7239666b9ba1151ab476cabb96c60d5c", size = 9297166, upload-time = "2025-12-18T09:48:56.664Z" }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, +] + +[[package]] +name = "mkdocs-pymdownx-material-extras" +version = "2.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs-material" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f6/5199d1e251e15b3c554f46b5796d02870e129f524dc2f117e828c5444674/mkdocs_pymdownx_material_extras-2.8.tar.gz", hash = "sha256:7b22bb119cd9592f98d6c6d4d269506d9a68d7038355c71525aadc88169ee9fe", size = 26512, upload-time = "2025-03-16T14:24:50.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/78/0059cb24b62a3dd68293daea38acb2cb75415d5735a62d6d60f752cd00ed/mkdocs_pymdownx_material_extras-2.8-py3-none-any.whl", hash = "sha256:81b68789420c51b9b15514180d0f3ab7136d56ee512c830c998d2edb77ca3d77", size = 28846, upload-time = "2025-03-16T14:24:49.235Z" }, +] + +[[package]] +name = "mkdocs-section-index" +version = "0.3.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/93/40/4aa9d3cfa2ac6528b91048847a35f005b97ec293204c02b179762a85b7f2/mkdocs_section_index-0.3.10.tar.gz", hash = "sha256:a82afbda633c82c5568f0e3b008176b9b365bf4bd8b6f919d6eff09ee146b9f8", size = 14446, upload-time = "2025-04-05T20:56:45.387Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/53/76c109e6f822a6d19befb0450c87330b9a6ce52353de6a9dda7892060a1f/mkdocs_section_index-0.3.10-py3-none-any.whl", hash = "sha256:bc27c0d0dc497c0ebaee1fc72839362aed77be7318b5ec0c30628f65918e4776", size = 8796, upload-time = "2025-04-05T20:56:43.975Z" }, +] + +[[package]] +name = "mkdocstrings" +version = "0.28.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocs-get-deps" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e3/48/d134ffefd61349ac96161078d836c7e0c15062e01104327c9a5b23398a0f/mkdocstrings-0.28.3.tar.gz", hash = "sha256:c753516b1b6cee12d00bf9c28255e22c0d71f34c721ca668971fce885d846e0f", size = 104109, upload-time = "2025-03-08T21:43:21.088Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/5c/205e4991fad1fbfe78b0d1fcfcf85f55556bcc93a5d6d94c7935e8463b87/mkdocstrings-0.28.3-py3-none-any.whl", hash = "sha256:df5351ffd10477aa3c2ff5cdf17544b936477195436923660274d084a5c1359c", size = 35177, upload-time = "2025-03-08T21:43:19.355Z" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "1.16.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffe" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/ed/b886f8c714fd7cccc39b79646b627dbea84cd95c46be43459ef46852caf0/mkdocstrings_python-1.16.12.tar.gz", hash = "sha256:9b9eaa066e0024342d433e332a41095c4e429937024945fea511afe58f63175d", size = 206065, upload-time = "2025-06-03T12:52:49.276Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/dd/a24ee3de56954bfafb6ede7cd63c2413bb842cc48eb45e41c43a05a33074/mkdocstrings_python-1.16.12-py3-none-any.whl", hash = "sha256:22ded3a63b3d823d57457a70ff9860d5a4de9e8b1e482876fc9baabaf6f5f374", size = 124287, upload-time = "2025-06-03T12:52:47.819Z" }, +] + [[package]] name = "multidict" version = "6.7.0" @@ -1451,13 +1805,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, +] + [[package]] name = "pathspec" -version = "0.12.1" +version = "1.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/b2/bb8e495d5262bfec41ab5cb18f522f1012933347fb5d9e62452d446baca2/pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d", size = 130841, upload-time = "2026-01-09T15:46:46.009Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, + { url = "https://files.pythonhosted.org/packages/32/2b/121e912bd60eebd623f873fd090de0e84f322972ab25a7f9044c056804ed/pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c", size = 55021, upload-time = "2026-01-09T15:46:44.652Z" }, ] [[package]] @@ -1795,6 +2158,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/fd/f4a4d9b8ea16d59a3d6a76469983d5a88cfeb58959e09c08402baae2da3a/pyloot-0.1.0-py3-none-any.whl", hash = "sha256:7173439ad6c4adbd7019af93fae79efc96b2a7ccaff5363238246c588cd05f12", size = 189880, upload-time = "2022-12-05T20:28:14.541Z" }, ] +[[package]] +name = "pymdown-extensions" +version = "10.20" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3e/35/e3814a5b7df295df69d035cfb8aab78b2967cdf11fcfae7faed726b66664/pymdown_extensions-10.20.tar.gz", hash = "sha256:5c73566ab0cf38c6ba084cb7c5ea64a119ae0500cce754ccb682761dfea13a52", size = 852774, upload-time = "2025-12-31T19:59:42.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/10/47caf89cbb52e5bb764696fd52a8c591a2f0e851a93270c05a17f36000b5/pymdown_extensions-10.20-py3-none-any.whl", hash = "sha256:ea9e62add865da80a271d00bfa1c0fa085b20d133fb3fc97afdc88e682f60b2f", size = 268733, upload-time = "2025-12-31T19:59:40.652Z" }, +] + [[package]] name = "pyparsing" version = "3.2.5" @@ -1923,6 +2299,30 @@ asyncio-client = [ { name = "aiohttp" }, ] +[[package]] +name = "pytokens" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/16/4b9cfd90d55e66ffdb277d7ebe3bc25250c2311336ec3fc73b2673c794d5/pytokens-0.4.0.tar.gz", hash = "sha256:6b0b03e6ea7c9f9d47c5c61164b69ad30f4f0d70a5d9fe7eac4d19f24f77af2d", size = 15039, upload-time = "2026-01-19T07:59:50.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/05/3196399a353dd4cd99138a88f662810979ee2f1a1cdb0b417cb2f4507836/pytokens-0.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:92eb3ef88f27c22dc9dbab966ace4d61f6826e02ba04dac8e2d65ea31df56c8e", size = 160075, upload-time = "2026-01-19T07:59:00.316Z" }, + { url = "https://files.pythonhosted.org/packages/28/1d/c8fc4ed0a1c4f660391b201cda00b1d5bbcc00e2998e8bcd48b15eefd708/pytokens-0.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f4b77858a680635ee9904306f54b0ee4781effb89e211ba0a773d76539537165", size = 247318, upload-time = "2026-01-19T07:59:01.636Z" }, + { url = "https://files.pythonhosted.org/packages/8e/0e/53e55ba01f3e858d229cd84b02481542f42ba59050483a78bf2447ee1af7/pytokens-0.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25cacc20c2ad90acb56f3739d87905473c54ca1fa5967ffcd675463fe965865e", size = 259752, upload-time = "2026-01-19T07:59:04.229Z" }, + { url = "https://files.pythonhosted.org/packages/dc/56/2d930d7f899e3f21868ca6e8ec739ac31e8fc532f66e09cbe45d3df0a84f/pytokens-0.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:628fab535ebc9079e4db35cd63cb401901c7ce8720a9834f9ad44b9eb4e0f1d4", size = 262842, upload-time = "2026-01-19T07:59:06.14Z" }, + { url = "https://files.pythonhosted.org/packages/42/dd/4e7e6920d23deffaf66e6f40d45f7610dcbc132ca5d90ab4faccef22f624/pytokens-0.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:4d0f568d7e82b7e96be56d03b5081de40e43c904eb6492bf09aaca47cd55f35b", size = 102620, upload-time = "2026-01-19T07:59:07.839Z" }, + { url = "https://files.pythonhosted.org/packages/3d/65/65460ebbfefd0bc1b160457904370d44f269e6e4582e0a9b6cba7c267b04/pytokens-0.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cd8da894e5a29ba6b6da8be06a4f7589d7220c099b5e363cb0643234b9b38c2a", size = 159864, upload-time = "2026-01-19T07:59:08.908Z" }, + { url = "https://files.pythonhosted.org/packages/25/70/a46669ec55876c392036b4da9808b5c3b1c5870bbca3d4cc923bf68bdbc1/pytokens-0.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:237ba7cfb677dbd3b01b09860810aceb448871150566b93cd24501d5734a04b1", size = 254448, upload-time = "2026-01-19T07:59:10.594Z" }, + { url = "https://files.pythonhosted.org/packages/62/0b/c486fc61299c2fc3b7f88ee4e115d4c8b6ffd1a7f88dc94b398b5b1bc4b8/pytokens-0.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01d1a61e36812e4e971cfe2c0e4c1f2d66d8311031dac8bf168af8a249fa04dd", size = 268863, upload-time = "2026-01-19T07:59:12.31Z" }, + { url = "https://files.pythonhosted.org/packages/79/92/b036af846707d25feaff7cafbd5280f1bd6a1034c16bb06a7c910209c1ab/pytokens-0.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e47e2ef3ec6ee86909e520d79f965f9b23389fda47460303cf715d510a6fe544", size = 267181, upload-time = "2026-01-19T07:59:13.856Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c0/6d011fc00fefa74ce34816c84a923d2dd7c46b8dbc6ee52d13419786834c/pytokens-0.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:3d36954aba4557fd5a418a03cf595ecbb1cdcce119f91a49b19ef09d691a22ae", size = 102814, upload-time = "2026-01-19T07:59:15.288Z" }, + { url = "https://files.pythonhosted.org/packages/98/63/627b7e71d557383da5a97f473ad50f8d9c2c1f55c7d3c2531a120c796f6e/pytokens-0.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:73eff3bdd8ad08da679867992782568db0529b887bed4c85694f84cdf35eafc6", size = 159744, upload-time = "2026-01-19T07:59:16.88Z" }, + { url = "https://files.pythonhosted.org/packages/28/d7/16f434c37ec3824eba6bcb6e798e5381a8dc83af7a1eda0f95c16fe3ade5/pytokens-0.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d97cc1f91b1a8e8ebccf31c367f28225699bea26592df27141deade771ed0afb", size = 253207, upload-time = "2026-01-19T07:59:18.069Z" }, + { url = "https://files.pythonhosted.org/packages/ab/96/04102856b9527701ae57d74a6393d1aca5bad18a1b1ca48ccffb3c93b392/pytokens-0.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c8952c537cb73a1a74369501a83b7f9d208c3cf92c41dd88a17814e68d48ce", size = 267452, upload-time = "2026-01-19T07:59:19.328Z" }, + { url = "https://files.pythonhosted.org/packages/0e/ef/0936eb472b89ab2d2c2c24bb81c50417e803fa89c731930d9fb01176fe9f/pytokens-0.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5dbf56f3c748aed9310b310d5b8b14e2c96d3ad682ad5a943f381bdbbdddf753", size = 265965, upload-time = "2026-01-19T07:59:20.613Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f5/64f3d6f7df4a9e92ebda35ee85061f6260e16eac82df9396020eebbca775/pytokens-0.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:e131804513597f2dff2b18f9911d9b6276e21ef3699abeffc1c087c65a3d975e", size = 102813, upload-time = "2026-01-19T07:59:22.012Z" }, + { url = "https://files.pythonhosted.org/packages/7c/3c/6941a82f4f130af6e1c68c076b6789069ef10c04559bd4733650f902fd3b/pytokens-0.4.0-py3-none-any.whl", hash = "sha256:0508d11b4de157ee12063901603be87fb0253e8f4cb9305eb168b1202ab92068", size = 13224, upload-time = "2026-01-19T07:59:49.822Z" }, +] + [[package]] name = "pyturbojpeg" version = "1.8.2" @@ -1978,6 +2378,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, ] +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, +] + +[[package]] +name = "rcslice" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/3e/abe47d91d5340b77b003baf96fdf8966c946eb4c5a704a844b5d03e6e578/rcslice-1.1.0.tar.gz", hash = "sha256:a2ce70a60690eb63e52b722e046b334c3aaec5e900b28578f529878782ee5c6e", size = 4414, upload-time = "2018-09-27T12:44:06.601Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/96/7935186fba032312eb8a75e6503440b0e6de76c901421f791408e4debd93/rcslice-1.1.0-py3-none-any.whl", hash = "sha256:1b12fc0c0ca452e8a9fd2b56ac008162f19e250906a4290a7e7a98be3200c2a6", size = 5180, upload-time = "2018-09-27T12:44:05.197Z" }, +] + [[package]] name = "requests" version = "2.32.5" @@ -2157,6 +2578,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d5/bb9997169b8b64d48f9a807fb2ec2413ff5e75c4b77612e75dd0aac8369c/suntime-1.3.2-py3-none-any.whl", hash = "sha256:33ac6ec2a3e14758cc690f7573f689d19c3131a6c9753f1bb54460bd70372ca4", size = 7211, upload-time = "2024-03-10T21:48:46.769Z" }, ] +[[package]] +name = "super-collections" +version = "0.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "hjson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/de/a0c3d1244912c260638f0f925e190e493ccea37ecaea9bbad7c14413b803/super_collections-0.6.2.tar.gz", hash = "sha256:0c8d8abacd9fad2c7c1c715f036c29f5db213f8cac65f24d45ecba12b4da187a", size = 31315, upload-time = "2025-09-30T00:37:08.067Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/43/47c7cf84b3bd74a8631b02d47db356656bb8dff6f2e61a4c749963814d0d/super_collections-0.6.2-py3-none-any.whl", hash = "sha256:291b74d26299e9051d69ad9d89e61b07b6646f86a57a2f5ab3063d206eee9c56", size = 16173, upload-time = "2025-09-30T00:37:07.104Z" }, +] + [[package]] name = "tabulate" version = "0.8.10" @@ -2166,6 +2599,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/92/4e/e5a13fdb3e6f81ce11893523ff289870c87c8f1f289a7369fb0e9840c3bb/tabulate-0.8.10-py3-none-any.whl", hash = "sha256:0ba055423dbaa164b9e456abe7920c5e8ed33fcc16f6d1b2f2d152c8e1e8b4fc", size = 29068, upload-time = "2022-06-21T16:26:37.943Z" }, ] +[[package]] +name = "termcolor" +version = "3.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, +] + [[package]] name = "tinycss2" version = "1.5.1" @@ -2178,6 +2620,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/60/45/c7b5c3168458db837e8ceab06dc77824e18202679d0463f0e8f002143a97/tinycss2-1.5.1-py3-none-any.whl", hash = "sha256:3415ba0f5839c062696996998176c4a3751d18b7edaaeeb658c9ce21ec150661", size = 28404, upload-time = "2025-11-23T10:29:08.676Z" }, ] +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, +] + [[package]] name = "tomlkit" version = "0.13.3" @@ -2303,6 +2754,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, ] +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] + [[package]] name = "watchfiles" version = "1.1.1" From 723e577f2cef32fb1bb9f6b9280804e9bc7c4ef3 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 19:56:04 +0100 Subject: [PATCH 06/26] fix reload --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index 758fc57..d5c9226 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -56,3 +56,4 @@ plugins: - "!^_[^_]" watch: - feldfreund_devkit + - docs From 55f14bde492a9b4abad159afc663577cf8c176a5 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 19:56:12 +0100 Subject: [PATCH 07/26] rewrite index --- docs/index.md | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/docs/index.md b/docs/index.md index 2c5a178..5a14740 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,18 +1,13 @@ # About -**Zauberzeug Field Friend** is an autonomous, mobile, and AI-driven agricultural robot developed by [Zauberzeug GmbH](https://zauberzeug.com). -The robot is specifically designed for autonomous actions, combining lightness, flexibility, and robustness -to efficiently handle a variety of outdoor tasks. -Equipped with advanced sensor technologies and camera systems, -the Field Friend can precisely determine its position, follow crop lines and detect various kinds of plants. -With it's modular design, the Field Friend can be extended with various tools and sensors to fit the specific needs of the use case. +The **Feldfreund DevKit** is an open-source platform for autonomous outdoor robotics developed by [Zauberzeug GmbH](https://zauberzeug.com). +Built on [RoSys](https://rosys.io), an all-Python robot system framework with built-in simulation, hardware abstraction, and a real-time web interface via [NiceGUI](https://nicegui.io/). +Time-critical and safety-critical behavior runs on the microcontroller via [Lizard](https://lizard.dev), a domain-specific language for embedded hardware control. + +Our agricultural weeding robot [Feldfreund](https://zauberzeug.com/feldfreund) is based on this platform and is intended to advance organic and regenerative agriculture. ## Features -- The Open Source software encourages you to modify and enhance the behavior and adapt it to your specific needs. -- The Modular Design allows equipping with tools from Zauberzeug as well as third-party solutions or your own developments. -- Advanced Sensing and Autonomy-Algorithms allows autonomous navigation and obstacle avoidance. -- Full control via web interface remote and locally via WiFi. -- Manual steering with touch-joystick and keyboard or App. -- A combined camera/motor calibration for real world coordinate system (unit: meters) -- ... +- **Open Source** — modify and enhance the software to fit your specific needs. +- **Modular Design** — equip with tools from Zauberzeug, third-party solutions, or custom developments. +- **ROS2 Support** — a [ROS2 implementation](https://github.com/zauberzeug/feldfreund_devkit_ros) is available. From 94fe9d8d2fba8c1031519518ab1c6d94b031fd3e Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 19:57:15 +0100 Subject: [PATCH 08/26] add livesync --- pyproject.toml | 1 + uv.lock | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 66902e8..8cc4956 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ dev = [ "ruff (>=0.13.2, <1.0.0)", "autopep8 (>=2.3.2, <3.0.0)", "poetry-dynamic-versioning (>=1.8.0, <2.0.0)", + "livesync (>=0.3.4, <1.0.0)", ] test = [ "pytest (>=8.3.4, <9.0.0)", diff --git a/uv.lock b/uv.lock index 0c8c58d..77a97db 100644 --- a/uv.lock +++ b/uv.lock @@ -602,6 +602,7 @@ dependencies = [ [package.dev-dependencies] dev = [ { name = "autopep8" }, + { name = "livesync" }, { name = "mypy" }, { name = "poetry-dynamic-versioning" }, { name = "pre-commit" }, @@ -645,6 +646,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "autopep8", specifier = ">=2.3.2,<3.0.0" }, + { name = "livesync", specifier = ">=0.3.4,<1.0.0" }, { name = "mypy", specifier = ">=1.18.2,<2.0.0" }, { name = "poetry-dynamic-versioning", specifier = ">=1.8.0,<2.0.0" }, { name = "pre-commit", specifier = ">=4.3.0,<5.0.0" }, @@ -1136,6 +1138,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/23/9c/ab8a94c30c082caca87bc0db78efe91372e45d35a700ef07ffe78ed10cda/line_profiler-4.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:727e970d358616a1a33d51d696efec932a5ef7730785df62658bd7e74aa58951", size = 128232, upload-time = "2024-12-03T17:11:51.741Z" }, ] +[[package]] +name = "livesync" +version = "0.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pathspec" }, + { name = "watchfiles" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/d6/fed2ee6f4b1ec828c8c5c4775d3d4384599dc4bc349416a67d3ba2ef312d/LiveSync-0.3.4.tar.gz", hash = "sha256:1748c4b2ce7820a6307b0e984a2d7844d74fa8f4a0c4d8f0e6b9a05a3aea34bb", size = 7223, upload-time = "2024-07-04T16:14:30.348Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/fe/c5bfc498121735833ad21bb1b65ad52daf913c9a18b71d672c71c38074c0/LiveSync-0.3.4-py3-none-any.whl", hash = "sha256:aa6d529fc281a82b6640171f566b6c20b3d29edc3fb51cf5e1bbd5f2b13b448b", size = 9111, upload-time = "2024-07-04T16:14:28.852Z" }, +] + [[package]] name = "markdown" version = "3.10" From c739ed8e9b7ba1c52c06b1f8feda81623ef5c066 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 20:23:05 +0100 Subject: [PATCH 09/26] cleanup --- docs/contributing.md | 85 -------------------------------------- docs/generate_reference.py | 2 + docs/getting_started.md | 75 --------------------------------- docs/index.md | 4 ++ docs/troubleshooting.md | 47 +++++---------------- mkdocs.yml | 2 - 6 files changed, 17 insertions(+), 198 deletions(-) delete mode 100644 docs/contributing.md delete mode 100644 docs/getting_started.md diff --git a/docs/contributing.md b/docs/contributing.md deleted file mode 100644 index 5cde196..0000000 --- a/docs/contributing.md +++ /dev/null @@ -1,85 +0,0 @@ -# Contributing - -We're thrilled that you're interested in contributing to the Field Friend source code! -Here are some guidelines that will help you get started. - -## Reporting issues - -If you encounter a bug or other issue, the best way to report it is by opening a new issue on our [GitHub repository](https://github.com/zauberzeug/feldfreund). -When creating the issue, please provide a clear and concise description of the problem, including any relevant error messages and code snippets. -If possible, include steps to reproduce the issue. - -## Code of Conduct - -We follow a [Code of Conduct](https://github.com/zauberzeug/feldfreund/blob/main/CODE_OF_CONDUCT.md) to ensure that everyone who participates in the NiceGUI community feels welcome and safe. -By participating, you agree to abide by its terms. - -## Contributing code - -We are excited that you want to contribute code to the Field Friend source code. -We're always looking for bug fixes, performance improvements, and new features. - -## Coding Style Guide - -### Formatting - -We use [autopep8](https://github.com/hhatto/autopep8) with a 120 character line length to format our code. -Before submitting a pull request, please run - -```bash -autopep8 --max-line-length=120 --in-place --recursive . -``` - -on your code to ensure that it meets our formatting guidelines. -Alternatively you can use VSCode, open the feldfreund.code-workspace file and install the recommended extensions. -Then the formatting rules are applied whenever you save a file. - -In our point of view, the Black formatter is sometimes a bit too strict. -There are cases where one or the other arrangement of, e.g., function arguments is more readable than the other. -Then we like the flexibility to either put all arguments on separate lines or only put the lengthy event handler -on a second line and leave the other arguments as they are. - -### Imports - -We use [ruff](https://docs.astral.sh/ruff/) to automatically sort imports: - -```bash -ruff check . --fix -``` - -### Single vs Double Quotes - -Regarding single or double quotes: [PEP 8](https://peps.python.org/pep-0008/) doesn't give any recommendation, so we simply chose single quotes and sticked with it. -On qwerty keyboards it's a bit easier to type, is visually less cluttered, and it works well for strings containing double quotes from the English language. - -### F-Strings - -We use f-strings where ever possible because they are generally more readable - once you get used to them. -There are only a few places in the code base where performance really matters and f-strings might not be the best choice. -These places should be marked with a `# NOTE: ...` comment when diverging from f-string usage. - -## Documentation - -### Formatting - -Because it has [numerous benefits](https://nick.groenen.me/notes/one-sentence-per-line/) we write each sentence in a new line. - -### Examples - -Each example should be about one concept. -Please try to make them as minimal as possible to show what is needed to get some kind of functionality. -We are happy to merge pull requests with new examples which show new concepts, ideas or interesting use cases. - -## Pull requests - -To get started, fork the repository on GitHub, clone it somewhere on your filesystem, commit and push your changes, -and then open a pull request (PR) with a detailed description of the changes you've made -(the PR button is shown on the GitHub website of your forked repository). - -When submitting a PR, please make sure that the code follows the existing coding style and that all tests are passing. -If you're adding a new feature, please include tests that cover the new functionality. - -## Thank you! - -Thank you for your interest in contributing. -We're looking forward to work with you! diff --git a/docs/generate_reference.py b/docs/generate_reference.py index b1d5bb5..10e4134 100644 --- a/docs/generate_reference.py +++ b/docs/generate_reference.py @@ -25,6 +25,8 @@ def extract_events(filepath: str) -> dict[str, str]: for path in sorted(Path('.').rglob('__init__.py')): + if any(part.startswith('.') for part in path.parts): + continue identifier = str(path.parent).replace('/', '.') if identifier in ['feldfreund_devkit',]: continue diff --git a/docs/getting_started.md b/docs/getting_started.md deleted file mode 100644 index fda8f4e..0000000 --- a/docs/getting_started.md +++ /dev/null @@ -1,75 +0,0 @@ -# Getting Started - -## Run in Simulation - -We suggest you begin with simulating the Field Friend on your local development machine. -The software is meant to run on Linux and Unix systems so if you are using Windows, consider running in a Docker container or virtual machine. - -The Field Friend requires either Linux or Mac system with Python {{ python_version }} to run.
Windows is currently not supported, but may work by using Docker or a virtual machine. - -1. Clone the repository
`git clone git@github.com:zauberzeug/feldfreund.git && cd feldfreund` - -2. Create a file with your environment variables and replace `U4` with the name of your robot
`echo "ROBOT_ID=U4" > .env` - -Now you have two options, either you run the code in Docker, like it does on the robot, or you setup your local python environment to run it. -Should you face any problems during the setup, please check the [troubleshooting page](troubleshooting.md) or submit a [GitHub issue](https://github.com/zauberzeug/feldfreund/issues). - -### Docker Setup (recommended) - -1. Install [Docker](https://docs.docker.com/get-started/get-docker/) - -2. Build and start the container.
`./docker.sh U`
Our `docker.sh` script will automatically use the correct settings for your system. - -### Local Setup - -1. Optional: Setup a virtual environment with [venv](https://docs.python.org/3/library/venv.html)
`python3 -m venv .venv && source .venv/bin/activate` - -2. Install the python requirements
`python3 -m pip install -r requirements-dev.txt` - -3. Now you can run the program
`python3 main.py` - -In both cases, this will open the user interface of a simulated robot in your browser (if not browse to [http://localhost/](http://localhost/)). -The simulation will automatically hot reload upon code changes. -The Field Friend code is based on [RoSys](https://rosys.io) which itself uses [NiceGUI](https://nicegui.io), -both having a very gentle learning curve and are designed to boost your rapid development and testing. - -## Run on Real Hardware - -The following instructions will only work if you have a real Zauberzeug Field Friend at your disposal. -Contact [sales@zauberzeug.com](mailto:sales@zauberzeug.com) if you are interested in purchasing this robot. - -### Setup - -1. Ensure you can login via ssh without providing a password (via `ssh-copy-id` command) -2. Ensure you have [LiveSync](https://github.com/zauberzeug/livesync) installed with
`python3 -m pip install livesync` -3. Ensure the latest version of the docker image is installed on the Field Friend by syncing the code as described below and then running
`./docker.sh U` -4. Optional: ensure the correct docker containers are loaded on startup by running
`./docker.sh stopall && ./docker.sh U && ./docker.sh install` - - - -### Deploy and Change Code - -1. Go to your local `feldfreund` folder and start the [LiveSync](https://github.com/zauberzeug/livesync) script:
- `./sync.py ` -2. This will deploy your local code to the Field Friend -3. As long as [LiveSync](https://github.com/zauberzeug/livesync) is active, all code change are automatically pushed to the machine -4. Any code changes will automatically trigger a hot reload on the Field Friend. - -### Update RoSys and NiceGUI - -To utilize personal versions of RoSys and NiceGUI instead of the default ones provided in the docker image, -modify the `sync.py` file by uncommenting the specific folders. - -### Logs - -You can see the current log with - -```bash -./docker.sh l rosys -``` - -The history of logs can be seen with - -```bash -less -r ~/.rosys/debug.log -``` diff --git a/docs/index.md b/docs/index.md index 5a14740..741409a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,6 +6,10 @@ Time-critical and safety-critical behavior runs on the microcontroller via [Liza Our agricultural weeding robot [Feldfreund](https://zauberzeug.com/feldfreund) is based on this platform and is intended to advance organic and regenerative agriculture. +**This documentation is currently work in progress while we try to expand this library.** + +Stay tuned and please [report any issues on Github](https://github.com/zauberzeug/feldfreund_devkit/issues). + ## Features - **Open Source** — modify and enhance the software to fit your specific needs. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 8104792..3e14694 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -1,51 +1,26 @@ # Troubleshooting -This section provides guidance for diagnosing and resolving issues during operation. Begin by checking the robot’s logs for warnings or errors. +This section provides guidance for diagnosing and resolving issues during operation. +If your issue is not listed here, you can also check the [RoSys documentation](https://rosys.io/troubleshooting/). -Live logs can be viewed using `docker.sh l rosys`, and archived logs are stored on the robot inside the `~/.rosys` directory. If further detail is required, enable debug-level logging on the [RoSys Logging Page](https://rosys.io/reference/rosys/analysis/#rosys.analysis.logging_page.LoggingPage) that is available at [/logging](http://localhost/logging). +## Logs -## Asyncio Warning +Check the logs for warnings or errors. Archived logs are stored in the `~/.rosys` directory. -While running RoSys you may see warnings similar to this one: +For more detail, enable debug-level logging on the [RoSys Logging Page](https://rosys.io/reference/rosys/analysis/#rosys.analysis.logging_page.LoggingPage) available at [/logging](http://localhost:8080/logging). -``` -2021-10-31 15:08:04.040 [WARNING] asyncio: Executing wait_for=<_GatheringFuture pending cb=[()] created at /usr/local/lib/python3.9/asyncio/tasks.py:705> created at /usr/local/lib/python3.9/site-packages/justpy/justpy.py:261> took 0.238 seconds -``` - -This means some coroutine is clogging the event loop for too long. -In the above example it is a whopping 238 ms in which no other actor can do anything. -This is an eternity when machine communication is expected to happen about every 10 ms. -The warning also provides a (not so readable) hint where the time is consumed. - -The example above is one of the more frequent scenarios. -It means some code inside a user interaction event handler (e.g. `handle_event()` in `justpy.py`) is blocking. -Try to figure out which UI event code is responsible by commenting out parts of your logic and try to reproduce the warning systematically. - -## CairoSVG on Mac +## Permission denied directly after startup -If [CairoSVG](https://cairosvg.org/) was installed via [Homebrew](https://brew.sh/), python sometimes can't find the correct path to run CairoSVG. -This will create a symbolic link to make the library accessible. +If you get the `[Errno 13] Permission denied` error message right after you started `main.py`, your system is probably blocking the default port 80. +Set a custom port via environment variable: ```bash -sudo mkdir -p /usr/local/lib && sudo ln -sf /opt/homebrew/lib/libcairo.2.dylib /usr/local/lib/libcairo.2.dylib +PORT=8080 uv run ./main.py ``` -You can test it with this command: - -```python -python3 -c "import cairocffi; import cairosvg; print('Cairo packages successfully imported!')" -``` - -## Missing Linux dependencies when running locally - -In case your Linux system is missing dependencies, look at the first lines of the provided [Dockerfile](https://github.com/zauberzeug/feldfreund/blob/main/Dockerfile) to find them. - -## Permission denied directly after startup - -If you get the `[Errno 13] Permission denied` error message right after you started `main.py`, your system is probably blocking the default port 80. -Try setting a custom port in your `.env`-file, like this +Or add it to a `.env` file: ``` -ROBOT_ID=U4 +ROBOT_ID=my_robot PORT=8080 ``` diff --git a/mkdocs.yml b/mkdocs.yml index d5c9226..b3c1afb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,13 +2,11 @@ site_name: Feldfreund Dev Kit Documentation site_url: https://docs.feldfreund.de/ nav: - index.md - - getting_started.md - Tutorials: - tutorials/tutorials.md - tutorials/imu_calibration.md - tutorials/odrive_calibration.md # - Module Reference: reference/ - - contributing.md - troubleshooting.md repo_url: https://github.com/zauberzeug/feldfreund_devkit edit_uri: edit/main/docs/ From b38cfc6915c607f72b6eae02ac8155372bb46411 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 21:44:46 +0100 Subject: [PATCH 10/26] add example --- main.py | 48 +++++++++++++++++++++++++++++++++++------------- pyproject.toml | 2 +- uv.lock | 6 +++--- 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/main.py b/main.py index 0780a77..69fa08a 100755 --- a/main.py +++ b/main.py @@ -1,21 +1,43 @@ #! /usr/bin/env python +import rosys from nicegui import app, ui -from rosys.analysis.logging_page import LoggingPage +from rosys.automation import Automator, automation_controls +from rosys.driving import Driver, Steerer, keyboard_control, robot_object + +import feldfreund_devkit +from feldfreund_devkit.config import FeldfreundConfiguration, config_from_id +from feldfreund_devkit.implement import ImplementDummy +from feldfreund_devkit.navigation import StraightLineNavigation + + +class System(feldfreund_devkit.System): + def __init__(self, config: FeldfreundConfiguration) -> None: + super().__init__(config) + self.steerer = Steerer(self.feldfreund.wheels, speed_scaling=0.25) + self.driver = Driver(self.feldfreund.wheels, self.odometer, parameters=self.config.driver) + self.shape = rosys.geometry.Prism.default_robot_shape() + self.navigation = StraightLineNavigation(implement=ImplementDummy(), + driver=self.driver, + pose_provider=self.odometer) + self.automator = Automator(self.steerer, on_interrupt=self.feldfreund.stop, notify=False) + self.automator.default_automation = self.navigation.start + + @ui.page('/') + def ui_content() -> None: + keyboard_control(self.steerer) + with ui.scene(): + robot_object(self.shape, self.odometer) + with ui.card(): + ui.label('hold SHIFT to steer with the keyboard arrow keys or use the automation controls') + with ui.row(): + self.navigation.settings_ui() + with ui.row(): + automation_controls(self.automator) def startup() -> None: - @ui.page('/') - def home_page() -> None: - ui.label('Hello to your new project: Feldfreund_devkit!').classes('text-4xl absolute-center') - - - logging_groups = ['Feldfreund_devkit', 'rosys', 'nicegui'] - LoggingPage(logging_groups) - - -@app.get('/status') -def status() -> dict[str, str]: - return {'status': 'ok'} + config = config_from_id('example') + System(config).persistent() app.on_startup(startup) diff --git a/pyproject.toml b/pyproject.toml index 8cc4956..ca76cdb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ readme = "README.md" requires-python = ">=3.11, <3.14" dependencies = [ "nicegui (>= 3.2.0, <4.0.0)", - "rosys @ git+https://github.com/zauberzeug/rosys.git@5298661def1a8dbe4b654c56a5334919d32cd9f3", + "rosys @ git+https://github.com/zauberzeug/rosys.git@7f3954faeef1b3152096f32ff07e97f5c50c379c", "httpx >=0.25.0", "coloredlogs", "httpcore", diff --git a/uv.lock b/uv.lock index 77a97db..897db58 100644 --- a/uv.lock +++ b/uv.lock @@ -640,7 +640,7 @@ requires-dist = [ { name = "httpx", specifier = ">=0.25.0" }, { name = "nicegui", specifier = ">=3.2.0,<4.0.0" }, { name = "psutil" }, - { name = "rosys", git = "https://github.com/zauberzeug/rosys.git?rev=5298661def1a8dbe4b654c56a5334919d32cd9f3" }, + { name = "rosys", git = "https://github.com/zauberzeug/rosys.git?rev=7f3954faeef1b3152096f32ff07e97f5c50c379c" }, ] [package.metadata.requires-dev] @@ -2431,8 +2431,8 @@ wheels = [ [[package]] name = "rosys" -version = "0.32.0.post2.dev0+5298661d" -source = { git = "https://github.com/zauberzeug/rosys.git?rev=5298661def1a8dbe4b654c56a5334919d32cd9f3#5298661def1a8dbe4b654c56a5334919d32cd9f3" } +version = "0.32.0.post4.dev0+7f3954fa" +source = { git = "https://github.com/zauberzeug/rosys.git?rev=7f3954faeef1b3152096f32ff07e97f5c50c379c#7f3954faeef1b3152096f32ff07e97f5c50c379c" } dependencies = [ { name = "aiohttp" }, { name = "cairosvg" }, From 7b38477636a36072db1eaaa80f3752b66569e7b3 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 22:19:56 +0100 Subject: [PATCH 11/26] fix docu --- docs/generate_reference.py | 31 +++++++++---------- docs/stylesheets/extra.css | 5 +++ feldfreund_devkit/api/online.py | 12 ++++--- .../config/camera_configuration.py | 14 ++++----- .../hardware/teltonika_router.py | 1 + .../navigation/straight_line_navigation.py | 1 + mkdocs.yml | 3 +- 7 files changed, 38 insertions(+), 29 deletions(-) diff --git a/docs/generate_reference.py b/docs/generate_reference.py index 10e4134..2a2f030 100644 --- a/docs/generate_reference.py +++ b/docs/generate_reference.py @@ -1,4 +1,3 @@ -import dataclasses import importlib import inspect import logging @@ -18,18 +17,17 @@ def extract_events(filepath: str) -> dict[str, str]: events_: dict[str, str] = {} for i, line in enumerate(lines): if re.search(r'= Event(\[.*?\])?\(\)$', line): - event_name_ = line.strip().split()[0].removeprefix('self.') - event_doc_ = lines[i+1].split('"""')[1] + event_name_ = line.strip().split()[0].removeprefix('self.').rstrip(':') + event_doc_ = lines[i + 1].split('"""')[1] events_[event_name_] = event_doc_ return events_ -for path in sorted(Path('.').rglob('__init__.py')): - if any(part.startswith('.') for part in path.parts): - continue +for path in sorted(Path('feldfreund_devkit').rglob('__init__.py')): identifier = str(path.parent).replace('/', '.') - if identifier in ['feldfreund_devkit',]: + if identifier == 'feldfreund_devkit': continue + try: module = importlib.import_module(identifier) except Exception: @@ -40,23 +38,22 @@ def extract_events(filepath: str) -> dict[str, str]: found_something = False for name in getattr(module, '__all__', dir(module)): if name.startswith('_'): - continue # skip private fields + continue cls = getattr(module, name) if isinstance(cls, ModuleType): - continue # skip sub-modules - if dataclasses.is_dataclass(cls): - continue # skip dataclasses + continue + if not inspect.isclass(cls): + continue if not cls.__doc__: - continue # skip classes without docstring + continue events = extract_events(inspect.getfile(cls)) with mkdocs_gen_files.open(Path('reference', doc_path), 'a') as fd: print(f'::: {identifier}.{name}', file=fd) - print(' options:', file=fd) - print(' filters:', file=fd) - print(' - "!^_[^_]"', file=fd) - for event_name in events: - print(f' - "!{event_name}"', file=fd) if events: + print(' options:', file=fd) + print(' filters:', file=fd) + for event_name in events: + print(f' - "!{event_name}"', file=fd) print('### Events', file=fd) print('Name | Description', file=fd) print('- | -', file=fd) diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 6d595d7..d6ae0ef 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -20,3 +20,8 @@ img { border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.25) 0 5px 10px; } + +/* Hide "Defaults" section from mkdocstrings */ +details.defaults { + display: none; +} diff --git a/feldfreund_devkit/api/online.py b/feldfreund_devkit/api/online.py index c57dba4..7fa315e 100644 --- a/feldfreund_devkit/api/online.py +++ b/feldfreund_devkit/api/online.py @@ -2,9 +2,13 @@ class Online: - """API endpoints for checking the robot's online status.""" + """API endpoints for checking the robot's online status. + + - `GET /api/online` → `{'online': True | False}` + """ def __init__(self) -> None: - @app.get('/api/online') - def connected(): - return {'online': True} + app.get('/api/online')(self.online) + + def online(self) -> dict[str, bool]: + return {'online': True} diff --git a/feldfreund_devkit/config/camera_configuration.py b/feldfreund_devkit/config/camera_configuration.py index 11e2329..30314cc 100644 --- a/feldfreund_devkit/config/camera_configuration.py +++ b/feldfreund_devkit/config/camera_configuration.py @@ -33,12 +33,12 @@ class CircleSightPositions: class CameraConfiguration: """Configuration for the camera of the Field Friend robot. - Attributes: - camera_type: default = 'CalibratableUsbCamera' - auto_exposure: default = True - rotation: default = 0 - fps: default = 10 - crop: default = None + Defaults: + camera_type: 'CalibratableUsbCamera' + auto_exposure: True + rotation: 0 + fps: 10 + crop: None """ width: int height: int @@ -50,7 +50,7 @@ class CameraConfiguration: @property def crop_rectangle(self) -> Rectangle | None: - """get a rectangle based on the crop values (left, right, up, down) of the config""" + """Get a rectangle based on the crop values (left, right, up, down) of the config""" if self.crop is None: return None new_width = self.width - (self.crop.left + self.crop.right) diff --git a/feldfreund_devkit/hardware/teltonika_router.py b/feldfreund_devkit/hardware/teltonika_router.py index e7b0749..36074d4 100644 --- a/feldfreund_devkit/hardware/teltonika_router.py +++ b/feldfreund_devkit/hardware/teltonika_router.py @@ -8,6 +8,7 @@ class ConnectionStatus(Enum): + """Connection status of the Teltonika router.""" ETHER = 'ether' WIFI = 'wifi' MOBILE = 'mobile' diff --git a/feldfreund_devkit/navigation/straight_line_navigation.py b/feldfreund_devkit/navigation/straight_line_navigation.py index e132932..9c7e85f 100644 --- a/feldfreund_devkit/navigation/straight_line_navigation.py +++ b/feldfreund_devkit/navigation/straight_line_navigation.py @@ -7,6 +7,7 @@ class StraightLineNavigation(WaypointNavigation): + """Navigation that drives a straight line for a given length.""" LENGTH: float = 2.0 def __init__(self, **kwargs) -> None: diff --git a/mkdocs.yml b/mkdocs.yml index b3c1afb..34eb5c5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,7 +6,7 @@ nav: - tutorials/tutorials.md - tutorials/imu_calibration.md - tutorials/odrive_calibration.md - # - Module Reference: reference/ + - Module Reference: reference/ - troubleshooting.md repo_url: https://github.com/zauberzeug/feldfreund_devkit edit_uri: edit/main/docs/ @@ -50,6 +50,7 @@ plugins: show_signature_annotations: true merge_init_into_class: true separate_signature: true + docstring_section_style: list filters: - "!^_[^_]" watch: From 30809b015347e5593a1ab3270603e06207732c51 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 22:46:43 +0100 Subject: [PATCH 12/26] add more docs --- docs/generate_reference.py | 7 +++++- .../config/feldfreund_configuration.py | 1 + feldfreund_devkit/feldfreund.py | 6 +++++ feldfreund_devkit/hardware/flashlight.py | 7 ++++++ feldfreund_devkit/hardware/safety.py | 25 ++++++++++++++++--- feldfreund_devkit/hardware/tracks.py | 8 ++---- feldfreund_devkit/implement.py | 5 +++- .../interface/components/confirm_dialog.py | 8 ++---- .../interface/components/header_bar.py | 2 ++ .../interface/components/log_monitor.py | 2 ++ .../interface/components/status_bulb.py | 2 ++ feldfreund_devkit/navigation/drive_segment.py | 2 +- feldfreund_devkit/robot_locator.py | 2 ++ 13 files changed, 59 insertions(+), 18 deletions(-) diff --git a/docs/generate_reference.py b/docs/generate_reference.py index 2a2f030..237ab37 100644 --- a/docs/generate_reference.py +++ b/docs/generate_reference.py @@ -47,8 +47,13 @@ def extract_events(filepath: str) -> dict[str, str]: if not cls.__doc__: continue events = extract_events(inspect.getfile(cls)) + if cls.__name__ != name: + cls_module = cls.__module__ + doc_identifier = f'{cls_module}.{cls.__name__}' + else: + doc_identifier = f'{identifier}.{name}' with mkdocs_gen_files.open(Path('reference', doc_path), 'a') as fd: - print(f'::: {identifier}.{name}', file=fd) + print(f'::: {doc_identifier}', file=fd) if events: print(' options:', file=fd) print(' filters:', file=fd) diff --git a/feldfreund_devkit/config/feldfreund_configuration.py b/feldfreund_devkit/config/feldfreund_configuration.py index 21cfaa2..af77369 100644 --- a/feldfreund_devkit/config/feldfreund_configuration.py +++ b/feldfreund_devkit/config/feldfreund_configuration.py @@ -18,6 +18,7 @@ @dataclass(kw_only=True) class FeldfreundConfiguration: + """Main configuration for a Feldfreund robot combining all module configurations.""" robot_id: str battery_control: BatteryControlConfiguration = field(default_factory=BatteryControlConfiguration) bluetooth: BluetoothConfiguration = field(default_factory=BluetoothConfiguration) diff --git a/feldfreund_devkit/feldfreund.py b/feldfreund_devkit/feldfreund.py index 7a743fa..406b134 100644 --- a/feldfreund_devkit/feldfreund.py +++ b/feldfreund_devkit/feldfreund.py @@ -53,6 +53,8 @@ class Feldfreund(Robot): + """Base class representing a Feldfreund robot with all its hardware modules.""" + def __init__(self, config: FeldfreundConfiguration, *, bms: Bms, bumper: Bumper | None, @@ -89,6 +91,8 @@ async def stop(self) -> None: class FeldfreundHardware(Feldfreund, RobotHardware): + """Hardware implementation of a Feldfreund robot with real hardware modules.""" + def __init__(self, config: FeldfreundConfiguration, **kwargs) -> None: communication = SerialCommunication() robot_brain = RobotBrain(communication, @@ -208,6 +212,8 @@ def _setup_flashlight(self, config: FlashlightConfiguration | FlashlightMosfetCo class FeldfreundSimulation(Feldfreund, RobotSimulation): + """Simulated Feldfreund robot for testing and development.""" + def __init__(self, config: FeldfreundConfiguration, *, use_acceleration: bool = False, **kwargs) -> None: wheels = TracksSimulation(config.wheels.width) if use_acceleration \ else WheelsSimulation(config.wheels.width) diff --git a/feldfreund_devkit/hardware/flashlight.py b/feldfreund_devkit/hardware/flashlight.py index fcc08d2..d02b6c8 100644 --- a/feldfreund_devkit/hardware/flashlight.py +++ b/feldfreund_devkit/hardware/flashlight.py @@ -9,6 +9,8 @@ class Flashlight(rosys.hardware.Module, abc.ABC): + """Base class for flashlight modules with on/off and duty cycle control.""" + def __init__(self, **kwargs) -> None: super().__init__(**kwargs) self._duty_cycle: float = 1.0 @@ -52,6 +54,8 @@ def developer_ui(self) -> None: class FlashlightHardware(Flashlight, rosys.hardware.ModuleHardware, SafetyMixin): + """Flashlight hardware implementation using PWM outputs.""" + def __init__(self, config: FlashlightConfiguration, robot_brain: rosys.hardware.RobotBrain, *, expander: rosys.hardware.ExpanderHardware | None) -> None: @@ -115,6 +119,8 @@ async def set_duty_cycle(self, duty_cycle: float) -> None: class FlashlightHardwareMosfet(Flashlight, rosys.hardware.ModuleHardware, SafetyMixin): + """Flashlight hardware implementation using a MOSFET switch.""" + UPDATE_INTERVAL = 5.0 def __init__(self, config: FlashlightMosfetConfiguration, @@ -164,4 +170,5 @@ def developer_ui(self) -> None: class FlashlightSimulation(Flashlight, rosys.hardware.ModuleSimulation): + """Simulated flashlight for testing.""" ... diff --git a/feldfreund_devkit/hardware/safety.py b/feldfreund_devkit/hardware/safety.py index 21e8a00..9c26664 100644 --- a/feldfreund_devkit/hardware/safety.py +++ b/feldfreund_devkit/hardware/safety.py @@ -6,6 +6,11 @@ class SafetyMixin(ABC): + """Mixin for modules that integrate with the safety system. + + Implement `enable_code` and `disable_code` to return Lizard code snippets + that get injected into the safety module's `enable()` and `disable()` functions. + """ @property @abstractmethod @@ -19,7 +24,11 @@ def disable_code(self) -> str: class Safety(ABC): - """The safety module is a simple example for a representation of real or simulated robot hardware.""" + """Coordinates safety behavior across wheels, estop, bumper, and registered modules. + + Modules implementing `SafetyMixin` can be registered via `add_module()` to have their + enable/disable code automatically called when the safety state changes. + """ def __init__(self, *, wheels: rosys.hardware.Wheels, @@ -32,11 +41,21 @@ def __init__(self, *, self.modules = modules or [] def add_module(self, module: SafetyMixin) -> None: + """Register a module to be enabled/disabled with the safety system.""" self.modules.append(module) class SafetyHardware(Safety, rosys.hardware.ModuleHardware): - """This module implements safety hardware.""" + """Generates Lizard code for hardware safety with automatic enable/disable behavior. + + The generated code creates `enable()` and `disable()` functions that control + wheels and all registered `SafetyMixin` modules. State transitions: + + - E-stop or bumper triggered → `disable()` called + - E-stop and bumper released while disabled → `enable()` called + - No messages for 1s → wheels stop + - No messages for 20s → full disable (watchdog) + """ def __init__(self, robot_brain: rosys.hardware.RobotBrain, **kwargs) -> None: Safety.__init__(self, **kwargs) @@ -109,4 +128,4 @@ async def estop_released_safety_notifications(self, name: str) -> None: class SafetySimulation(Safety, rosys.hardware.ModuleSimulation): - ... + """Simulated safety module for testing.""" diff --git a/feldfreund_devkit/hardware/tracks.py b/feldfreund_devkit/hardware/tracks.py index 888753e..8afcc2d 100644 --- a/feldfreund_devkit/hardware/tracks.py +++ b/feldfreund_devkit/hardware/tracks.py @@ -137,13 +137,9 @@ def _ui() -> None: class TracksSimulation(WheelsSimulation): - def __init__(self, width: float = 0.5, *, linear_acceleration: float = 2.0, linear_deceleration: float = 0.5) -> None: - """Simulate differential drive wheels with acceleration and deceleration handling. + """Simulated tracks with acceleration and deceleration handling.""" - :param width: The distance between the wheels in meters. - :param linear_acceleration: The maximum linear acceleration rate in m/s². - :param linear_deceleration: The maximum linear deceleration rate in m/s². - """ + def __init__(self, width: float = 0.5, *, linear_acceleration: float = 2.0, linear_deceleration: float = 0.5) -> None: super().__init__(width) self.linear_acceleration: float = linear_acceleration diff --git a/feldfreund_devkit/implement.py b/feldfreund_devkit/implement.py index fb51fd0..a08e7d4 100644 --- a/feldfreund_devkit/implement.py +++ b/feldfreund_devkit/implement.py @@ -9,10 +9,11 @@ class ImplementException(Exception): - pass + """Raised when an implement operation fails.""" class Implement(rosys.persistence.Persistable): + """Base class for robot implements like weeding tools or cameras.""" def __init__(self, config: ImplementConfiguration) -> None: super().__init__() @@ -87,6 +88,8 @@ def developer_ui(self) -> None: class ImplementDummy(Implement): + """A no-op implement for testing or when no implement is attached.""" + def __init__(self) -> None: super().__init__(ImplementConfiguration(lizard_name='None', display_name='None', work_radius=0.0)) diff --git a/feldfreund_devkit/interface/components/confirm_dialog.py b/feldfreund_devkit/interface/components/confirm_dialog.py index 9d3d2fe..c526510 100644 --- a/feldfreund_devkit/interface/components/confirm_dialog.py +++ b/feldfreund_devkit/interface/components/confirm_dialog.py @@ -2,13 +2,9 @@ class ConfirmDialog(ui.dialog): - def __init__(self, text: str = 'Are you sure?', *, delay: float = 3.0) -> None: - """ - A dialog that asks for confirmation. + """A dialog that asks for confirmation with a delayed yes button.""" - :param text: The text to display in the dialog. - :param delay: The delay in seconds before the yes button is enabled. - """ + def __init__(self, text: str = 'Are you sure?', *, delay: float = 3.0) -> None: super().__init__() self.delay = delay with self, ui.card(): diff --git a/feldfreund_devkit/interface/components/header_bar.py b/feldfreund_devkit/interface/components/header_bar.py index 71007ac..6a323da 100644 --- a/feldfreund_devkit/interface/components/header_bar.py +++ b/feldfreund_devkit/interface/components/header_bar.py @@ -5,6 +5,8 @@ class HeaderBar: + """Navigation header with logo, page links, and status indicators.""" + def __init__(self, pages: dict[str, str] | None = None, *, estop: EStop | None = None, bms: Bms | None = None, diff --git a/feldfreund_devkit/interface/components/log_monitor.py b/feldfreund_devkit/interface/components/log_monitor.py index 308e571..99b44d3 100644 --- a/feldfreund_devkit/interface/components/log_monitor.py +++ b/feldfreund_devkit/interface/components/log_monitor.py @@ -7,6 +7,8 @@ class LogMonitor(rosys.persistence.Persistable): + """Persisted log display for notifications with timestamps.""" + MAX_LINES = 100 def __init__(self, *, max_lines: int = MAX_LINES) -> None: diff --git a/feldfreund_devkit/interface/components/status_bulb.py b/feldfreund_devkit/interface/components/status_bulb.py index 2a915fc..ec9c524 100644 --- a/feldfreund_devkit/interface/components/status_bulb.py +++ b/feldfreund_devkit/interface/components/status_bulb.py @@ -2,6 +2,8 @@ class StatusBulb(ValueElement): + """A circular LED-style indicator that changes color based on value.""" + def __init__(self, value: bool = False) -> None: super().__init__(value=value, on_value_change=self.on_change, tag='span') self.style('height: 15px; width: 15px; margin: auto; border-radius: 50%') diff --git a/feldfreund_devkit/navigation/drive_segment.py b/feldfreund_devkit/navigation/drive_segment.py index 6285585..3272fb6 100644 --- a/feldfreund_devkit/navigation/drive_segment.py +++ b/feldfreund_devkit/navigation/drive_segment.py @@ -7,7 +7,7 @@ @dataclass(slots=True, kw_only=True) class DriveSegment(PathSegment): - # TODO: move methods to rosys.driving.PathSegment + """A path segment with implement usage and stop behavior configuration.""" use_implement: bool = False stop_at_end: bool = True diff --git a/feldfreund_devkit/robot_locator.py b/feldfreund_devkit/robot_locator.py index 24ed006..41e3388 100644 --- a/feldfreund_devkit/robot_locator.py +++ b/feldfreund_devkit/robot_locator.py @@ -12,6 +12,8 @@ class RobotLocator(rosys.persistence.Persistable): + """Extended Kalman filter for robot pose estimation using odometry, GNSS, and IMU.""" + R_ODOM_LINEAR = 0.1 R_ODOM_ANGULAR = 0.097 R_IMU_ANGULAR = 0.01 From 62b938a970b5af090741e3d6d7911fdaa933dc6e Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 22:53:50 +0100 Subject: [PATCH 13/26] fix wording --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 741409a..47ef681 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,7 +6,7 @@ Time-critical and safety-critical behavior runs on the microcontroller via [Liza Our agricultural weeding robot [Feldfreund](https://zauberzeug.com/feldfreund) is based on this platform and is intended to advance organic and regenerative agriculture. -**This documentation is currently work in progress while we try to expand this library.** +**This documentation is currently work in progress while we expand this library.** Stay tuned and please [report any issues on Github](https://github.com/zauberzeug/feldfreund_devkit/issues). From 71ea5561c1a83776560351f7c7d77793e4a0ca17 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 22:53:55 +0100 Subject: [PATCH 14/26] add getting started --- docs/getting_started.md | 57 +++++++++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 58 insertions(+) create mode 100644 docs/getting_started.md diff --git a/docs/getting_started.md b/docs/getting_started.md new file mode 100644 index 0000000..e3893d2 --- /dev/null +++ b/docs/getting_started.md @@ -0,0 +1,57 @@ +# Getting Started + +## Installation + +Clone the repository and install dependencies with [uv](https://docs.astral.sh/uv/): + +```bash +git clone https://github.com/zauberzeug/feldfreund_devkit.git +cd feldfreund_devkit +uv sync +``` + +## Running the Example + +The repository includes a minimal example in `main.py` that demonstrates: + +- Robot simulation with keyboard control +- Straight line navigation automation +- Real-time 3D visualization + +Start it with: + +```bash +uv run main.py +``` + +Open [http://localhost:8080](http://localhost:8080) in your browser. Hold **SHIFT** and use the **arrow keys** to steer the robot, or use the automation controls to run a straight line navigation. + +## Understanding the Example + +```python +--8<-- "main.py" +``` + +The `System` class extends `feldfreund_devkit.System` which initializes the robot hardware (or simulation) based on the configuration. Key components: + +- **config**: Loaded from `config/example.py` via `config_from_id('example')` +- **steerer**: Manual steering control +- **driver**: Path-following driver for automations +- **navigation**: `StraightLineNavigation` drives forward for a configurable distance +- **automator**: Manages automation lifecycle (play/pause/stop) + +## Configuration + +Robot configurations live in the `config/` directory. See `config/example.py`: + +```python +--8<-- "config/example.py" +``` + +In simulation mode (when no hardware is detected), mock implementations are used automatically. + +## Next Steps + +- Browse the **Module Reference** in the navigation for API documentation +- Check the [Tutorials](tutorials/tutorials.md) for hardware calibration guides +- See [Troubleshooting](troubleshooting.md) for common issues diff --git a/mkdocs.yml b/mkdocs.yml index 34eb5c5..eaa9ac4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,6 +2,7 @@ site_name: Feldfreund Dev Kit Documentation site_url: https://docs.feldfreund.de/ nav: - index.md + - getting_started.md - Tutorials: - tutorials/tutorials.md - tutorials/imu_calibration.md From 0dfab7f14f60a6f3b928cca0ea11673a8ccf21cc Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 22:55:42 +0100 Subject: [PATCH 15/26] fix pylint --- feldfreund_devkit/hardware/flashlight.py | 1 - 1 file changed, 1 deletion(-) diff --git a/feldfreund_devkit/hardware/flashlight.py b/feldfreund_devkit/hardware/flashlight.py index d02b6c8..3577e3f 100644 --- a/feldfreund_devkit/hardware/flashlight.py +++ b/feldfreund_devkit/hardware/flashlight.py @@ -171,4 +171,3 @@ def developer_ui(self) -> None: class FlashlightSimulation(Flashlight, rosys.hardware.ModuleSimulation): """Simulated flashlight for testing.""" - ... From e1f9f0045efd2ba217658bd8ddd89cc275f0aace Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 23:31:59 +0100 Subject: [PATCH 16/26] fix docs --- docs/CNAME | 1 + docs/generate_reference.py | 68 ++++++++++++++++++++++++++-- feldfreund_devkit/hardware/tracks.py | 4 +- mkdocs.yml | 2 +- 4 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 docs/CNAME diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000..83d43ea --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +docs.feldfreund.de \ No newline at end of file diff --git a/docs/generate_reference.py b/docs/generate_reference.py index 237ab37..99024fa 100644 --- a/docs/generate_reference.py +++ b/docs/generate_reference.py @@ -23,6 +23,49 @@ def extract_events(filepath: str) -> dict[str, str]: return events_ +def format_type(hint) -> str: + if hint is None: + return '' + if hint is type(None): + return 'None' + if hasattr(hint, '__name__'): + return f'`{hint.__name__}`' + type_str = str(hint).replace('typing.', '').replace('NoneType', 'None') + return f'`{type_str}`' + + +def extract_properties(cls: type) -> dict[str, tuple[str, str]]: + props: dict[str, tuple[str, str]] = {} + for name, obj in inspect.getmembers(cls): + if name.startswith('_'): + continue + if isinstance(obj, property) and obj.fget is not None: + doc = obj.fget.__doc__ or '' + doc = doc.strip().split('\n')[0] if doc else '' + type_hint = obj.fget.__annotations__.get('return') + props[name] = (format_type(type_hint), doc) + return props + + +def extract_instance_attributes(filepath: str) -> dict[str, tuple[str, str]]: + """Extract instance attributes with their inline docstrings from source.""" + with open(filepath, encoding='utf-8') as f: + lines = f.read().splitlines() + attrs: dict[str, tuple[str, str]] = {} + for i, line in enumerate(lines): + match = re.match(r'\s+self\.(\w+)(?::\s*(\S+))?\s*=', line) + if match: + attr_name = match.group(1) + attr_type = match.group(2) or '' + if attr_name.startswith('_'): + continue + if i + 1 < len(lines) and '"""' in lines[i + 1]: + doc = lines[i + 1].split('"""')[1] + type_str = f'`{attr_type}`' if attr_type else '' + attrs[attr_name] = (type_str, doc) + return attrs + + for path in sorted(Path('feldfreund_devkit').rglob('__init__.py')): identifier = str(path.parent).replace('/', '.') if identifier == 'feldfreund_devkit': @@ -46,24 +89,39 @@ def extract_events(filepath: str) -> dict[str, str]: continue if not cls.__doc__: continue - events = extract_events(inspect.getfile(cls)) + source_file = inspect.getfile(cls) + events = extract_events(source_file) + properties = extract_properties(cls) + instance_attrs = extract_instance_attributes(source_file) if cls.__name__ != name: cls_module = cls.__module__ doc_identifier = f'{cls_module}.{cls.__name__}' else: doc_identifier = f'{identifier}.{name}' + properties = {k: v for k, v in properties.items() if v[1]} + instance_attrs = {k: v for k, v in instance_attrs.items() if v[1] and k not in events} + members = {**instance_attrs, **properties} + filters = list(events.keys()) + list(members.keys()) with mkdocs_gen_files.open(Path('reference', doc_path), 'a') as fd: print(f'::: {doc_identifier}', file=fd) - if events: + if filters: print(' options:', file=fd) print(' filters:', file=fd) - for event_name in events: - print(f' - "!{event_name}"', file=fd) + for filter_name in filters: + print(f' - "!{filter_name}"', file=fd) + if members: + print('### Attributes & Properties', file=fd) + print('Name | Type | Description', file=fd) + print('- | - | -', file=fd) + for member_name, (member_type, member_doc) in members.items(): + print(f'`{member_name}` | {member_type} | {member_doc}', file=fd) + print('', file=fd) + if events: print('### Events', file=fd) print('Name | Description', file=fd) print('- | -', file=fd) for event_name, event_doc in events.items(): - print(f'{event_name} | {event_doc}', file=fd) + print(f'`{event_name}` | {event_doc}', file=fd) print('', file=fd) found_something = True diff --git a/feldfreund_devkit/hardware/tracks.py b/feldfreund_devkit/hardware/tracks.py index 8afcc2d..22aedb1 100644 --- a/feldfreund_devkit/hardware/tracks.py +++ b/feldfreund_devkit/hardware/tracks.py @@ -150,12 +150,12 @@ def __init__(self, width: float = 0.5, *, linear_acceleration: float = 2.0, line @property def angular_acceleration(self) -> float: - """Calculate angular acceleration from linear acceleration using differential drive kinematics.""" + """Calculated angular acceleration from linear acceleration using differential drive kinematics.""" return 2 * self.linear_acceleration / self.width @property def angular_deceleration(self) -> float: - """Calculate angular deceleration from linear deceleration using differential drive kinematics.""" + """Calculated angular deceleration from linear deceleration using differential drive kinematics.""" return 2 * self.linear_deceleration / self.width async def drive(self, linear: float, angular: float) -> None: diff --git a/mkdocs.yml b/mkdocs.yml index eaa9ac4..bce2611 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -51,7 +51,7 @@ plugins: show_signature_annotations: true merge_init_into_class: true separate_signature: true - docstring_section_style: list + docstring_section_style: table filters: - "!^_[^_]" watch: From adb46352f81ced434e4bd1a7318ec35a72f17fd8 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 23:33:54 +0100 Subject: [PATCH 17/26] fix pre-commit --- docs/CNAME | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CNAME b/docs/CNAME index 83d43ea..095e7b6 100644 --- a/docs/CNAME +++ b/docs/CNAME @@ -1 +1 @@ -docs.feldfreund.de \ No newline at end of file +docs.feldfreund.de From 8859b0df107933fd8c72ccdab39b92a5bd9a046a Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 23:37:27 +0100 Subject: [PATCH 18/26] typo --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 47ef681..5e98cee 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ # About -The **Feldfreund DevKit** is an open-source platform for autonomous outdoor robotics developed by [Zauberzeug GmbH](https://zauberzeug.com). +The **Feldfreund Dev Kit** is an open-source platform for autonomous outdoor robotics developed by [Zauberzeug GmbH](https://zauberzeug.com). Built on [RoSys](https://rosys.io), an all-Python robot system framework with built-in simulation, hardware abstraction, and a real-time web interface via [NiceGUI](https://nicegui.io/). Time-critical and safety-critical behavior runs on the microcontroller via [Lizard](https://lizard.dev), a domain-specific language for embedded hardware control. From 34eb9d4dd7db1168156d22062ad306e5d22ef177 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 23:40:51 +0100 Subject: [PATCH 19/26] add mkdocs commands to makefile --- Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 31755d6..a917daf 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help sync install-ci mypy pylint pre-commit +.PHONY: help sync install-ci mypy pylint pre-commit docs-serve docs-deploy default: help @@ -36,3 +36,11 @@ pre-commit: ## check Run all code checks (mypy, pre-commit, pylint). check: mypy pre-commit pylint + +## docs-serve Serve documentation locally. +docs-serve: + uv run --active mkdocs serve + +## docs-deploy Deploy documentation to GitHub Pages. +docs-deploy: + uv run --active mkdocs gh-deploy --force From abd2804a3e518105472e54fde7be42e2bca5d25c Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 23:44:25 +0100 Subject: [PATCH 20/26] remove unnecessary script --- update_docs.sh | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 update_docs.sh diff --git a/update_docs.sh b/update_docs.sh deleted file mode 100644 index 0885492..0000000 --- a/update_docs.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -# Script to update documentation with information from pyproject.toml - -# Install required packages if not already installed -pip install -r docs_requirements.txt - -# Run the update script -python update_docs.py - -echo "Documentation update complete!" From 698366b463d896225320c1677093e06ab23a18f3 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 23:50:51 +0100 Subject: [PATCH 21/26] naming --- README.md | 2 +- docs/tutorials/imu_calibration.md | 2 +- docs/tutorials/tutorials.md | 2 +- feldfreund_devkit/config/battery_configuration.py | 4 ++-- feldfreund_devkit/config/bumper_configuration.py | 2 +- feldfreund_devkit/config/camera_configuration.py | 4 ++-- feldfreund_devkit/config/can_configuration.py | 2 +- feldfreund_devkit/config/estop_configuration.py | 2 +- feldfreund_devkit/config/gnss_configuration.py | 2 +- feldfreund_devkit/config/imu_configuration.py | 2 +- feldfreund_devkit/config/robot_brain_configuration.py | 2 +- feldfreund_devkit/hardware/tracks.py | 2 +- feldfreund_devkit/robot_locator.py | 2 +- 13 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 1182057..d0dea44 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Feldfreund rendering -# Feldfreund DevKit +# Feldfreund Dev Kit This is the source code of the [Feldfreund Dev Kit](https://zauberzeug.com/products/field-friend-dev-kit) for autonomous outdoor robotics made by [Zauberzeug](https://zauberzeug.com/). The software is based on [RoSys](https://rosys.io) and [NiceGUI](https://nicegui.io/). diff --git a/docs/tutorials/imu_calibration.md b/docs/tutorials/imu_calibration.md index 8cf5e95..9748c7c 100644 --- a/docs/tutorials/imu_calibration.md +++ b/docs/tutorials/imu_calibration.md @@ -30,7 +30,7 @@ print(f'imu=Imu(offset_rotation=Rotation.from_euler({complete_correction.roll:.6 Steps: 1. Find the correct base orientation of your IMU. - If your Field Friend has the standard configuration, you can use this as a starting point: + If your Feldfreund has the standard configuration, you can use this as a starting point: `Imu(offset_rotation=Rotation.from_euler(-1.570796, -0.000000, 1.570796))` 2. Roll and pitch your robot manually to check if the configuration is correct and the axes are correctly rotated. 3. Place your robot on a level surface and check the IMU's current values on the [development page](http://192.168.42.2/dev) diff --git a/docs/tutorials/tutorials.md b/docs/tutorials/tutorials.md index 97ea73b..60bb9cb 100644 --- a/docs/tutorials/tutorials.md +++ b/docs/tutorials/tutorials.md @@ -1,6 +1,6 @@ # Tutorials -Welcome to the Field Friend tutorials section! Here you'll find step-by-step guides to help you get the most out of your Field Friend robot. +Welcome to the Feldfreund tutorials section! Here you'll find step-by-step guides to help you get the most out of your Feldfreund robot. - [IMU calibration](imu_calibration.md) - How to determine the correct rotation for the ImuConfiguration - [ODrive calibration](odrive_calibration.md) - Let the ODrive motor controllers calibrate themselves diff --git a/feldfreund_devkit/config/battery_configuration.py b/feldfreund_devkit/config/battery_configuration.py index accc7d7..f67c154 100644 --- a/feldfreund_devkit/config/battery_configuration.py +++ b/feldfreund_devkit/config/battery_configuration.py @@ -3,7 +3,7 @@ @dataclass(slots=True, kw_only=True) class BatteryControlConfiguration: - """Configuration for the battery control of the Field Friend robot. + """Configuration for the battery control of the Feldfreund robot. Defaults: name: 'battery_control' @@ -19,7 +19,7 @@ class BatteryControlConfiguration: @dataclass(slots=True, kw_only=True) class BmsConfiguration: - """Configuration for the bms of the Field Friend robot. + """Configuration for the bms of the Feldfreund robot. Defaults: name: 'bms' diff --git a/feldfreund_devkit/config/bumper_configuration.py b/feldfreund_devkit/config/bumper_configuration.py index 8f51cf0..9f075f6 100644 --- a/feldfreund_devkit/config/bumper_configuration.py +++ b/feldfreund_devkit/config/bumper_configuration.py @@ -3,7 +3,7 @@ @dataclass(slots=True, kw_only=True) class BumperConfiguration: - """Configuration for the bumper of the Field Friend robot. + """Configuration for the bumper of the Feldfreund robot. Defaults: name: 'bumper' diff --git a/feldfreund_devkit/config/camera_configuration.py b/feldfreund_devkit/config/camera_configuration.py index 30314cc..1480fda 100644 --- a/feldfreund_devkit/config/camera_configuration.py +++ b/feldfreund_devkit/config/camera_configuration.py @@ -6,7 +6,7 @@ @dataclass(kw_only=True) class CropConfiguration: - """Configuration for the cropping of the camera of the Field Friend robot.""" + """Configuration for the cropping of the camera of the Feldfreund robot.""" left: int right: int up: int @@ -31,7 +31,7 @@ class CircleSightPositions: @dataclass(kw_only=True) class CameraConfiguration: - """Configuration for the camera of the Field Friend robot. + """Configuration for the camera of the Feldfreund robot. Defaults: camera_type: 'CalibratableUsbCamera' diff --git a/feldfreund_devkit/config/can_configuration.py b/feldfreund_devkit/config/can_configuration.py index 0503694..7443850 100644 --- a/feldfreund_devkit/config/can_configuration.py +++ b/feldfreund_devkit/config/can_configuration.py @@ -3,7 +3,7 @@ @dataclass(slots=True, kw_only=True) class CanConfiguration: - """Configuration for the can of the Field Friend robot. + """Configuration for the can of the Feldfreund robot. Defaults: name: 'can' diff --git a/feldfreund_devkit/config/estop_configuration.py b/feldfreund_devkit/config/estop_configuration.py index 2c3269a..8703006 100644 --- a/feldfreund_devkit/config/estop_configuration.py +++ b/feldfreund_devkit/config/estop_configuration.py @@ -3,7 +3,7 @@ @dataclass(slots=True, kw_only=True) class EstopConfiguration: - """Configuration for the estop of the Field Friend robot. + """Configuration for the estop of the Feldfreund robot. Defaults: name: 'estop' diff --git a/feldfreund_devkit/config/gnss_configuration.py b/feldfreund_devkit/config/gnss_configuration.py index e6d36ae..6e22f12 100644 --- a/feldfreund_devkit/config/gnss_configuration.py +++ b/feldfreund_devkit/config/gnss_configuration.py @@ -5,7 +5,7 @@ @dataclass(slots=True, kw_only=True) class GnssConfiguration: - """Configuration for the GNSS of the Field Friend robot. + """Configuration for the GNSS of the Feldfreund robot. X, Y, Z are the position of the main GNSS antenna. The yaw is the direction to the auxiliary antenna. diff --git a/feldfreund_devkit/config/imu_configuration.py b/feldfreund_devkit/config/imu_configuration.py index 02a531b..02cbe27 100644 --- a/feldfreund_devkit/config/imu_configuration.py +++ b/feldfreund_devkit/config/imu_configuration.py @@ -5,7 +5,7 @@ @dataclass(slots=True, kw_only=True) class ImuConfiguration: - """Configuration for the IMU of the Field Friend robot. + """Configuration for the IMU of the Feldfreund robot. Defaults: name: 'imu' diff --git a/feldfreund_devkit/config/robot_brain_configuration.py b/feldfreund_devkit/config/robot_brain_configuration.py index 1eb60fa..195b9f7 100644 --- a/feldfreund_devkit/config/robot_brain_configuration.py +++ b/feldfreund_devkit/config/robot_brain_configuration.py @@ -3,7 +3,7 @@ @dataclass(kw_only=True) class RobotBrainConfiguration: - """Configuration for the robot brain of the Field Friend robot. + """Configuration for the robot brain of the Feldfreund robot. Defaults: enable_esp_on_startup: False diff --git a/feldfreund_devkit/hardware/tracks.py b/feldfreund_devkit/hardware/tracks.py index 22aedb1..2fdc84a 100644 --- a/feldfreund_devkit/hardware/tracks.py +++ b/feldfreund_devkit/hardware/tracks.py @@ -8,7 +8,7 @@ class TracksHardware(Wheels, ModuleHardware): - """Expands the RoSys wheels hardware to control the field friend's tracked wheels with dual motors.""" + """Expands the RoSys wheels hardware to control the Feldfreund's tracked wheels with dual motors.""" MAX_VALID_LINEAR_VELOCITY = 3.0 MAX_VALID_ANGULAR_VELOCITY = 3.5 ERROR_FLAG_VERSION = 6 diff --git a/feldfreund_devkit/robot_locator.py b/feldfreund_devkit/robot_locator.py index 41e3388..74ffe84 100644 --- a/feldfreund_devkit/robot_locator.py +++ b/feldfreund_devkit/robot_locator.py @@ -162,7 +162,7 @@ def _handle_gnss_measurement(self, gnss_measurement: GnssMeasurement) -> None: return if not np.isfinite(gnss_measurement.heading_std_dev): # normally we would only handle the position if no heading is available, - # but the field friend needs the rtk accuracy to function properly + # but the Feldfreund needs the rtk accuracy to function properly return pose, r_xy, r_theta = self._get_local_pose_and_uncertainty(gnss_measurement) if self._auto_tilt_correction and isinstance(self._imu, Imu) and not self._ignore_imu and self._imu.last_measurement is not None: From eca1ec5b3f076c65ae68bce7c7a8f216a0661044 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Wed, 21 Jan 2026 23:54:17 +0100 Subject: [PATCH 22/26] remote site folder after deployment --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a917daf..4ad6cbd 100644 --- a/Makefile +++ b/Makefile @@ -43,4 +43,4 @@ docs-serve: ## docs-deploy Deploy documentation to GitHub Pages. docs-deploy: - uv run --active mkdocs gh-deploy --force + uv run --active mkdocs gh-deploy --force && rm -rf site From fbb2c76472322b64095daaabac74ba639c58f5b0 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Fri, 23 Jan 2026 12:13:58 +0100 Subject: [PATCH 23/26] fix page setup --- main.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/main.py b/main.py index 69fa08a..6d319c8 100755 --- a/main.py +++ b/main.py @@ -22,22 +22,22 @@ def __init__(self, config: FeldfreundConfiguration) -> None: self.automator = Automator(self.steerer, on_interrupt=self.feldfreund.stop, notify=False) self.automator.default_automation = self.navigation.start - @ui.page('/') - def ui_content() -> None: - keyboard_control(self.steerer) - with ui.scene(): - robot_object(self.shape, self.odometer) - with ui.card(): - ui.label('hold SHIFT to steer with the keyboard arrow keys or use the automation controls') - with ui.row(): - self.navigation.settings_ui() - with ui.row(): - automation_controls(self.automator) - def startup() -> None: config = config_from_id('example') - System(config).persistent() + system = System(config).persistent() + + @ui.page('/') + def ui_content() -> None: + keyboard_control(system.steerer) + with ui.scene(): + robot_object(system.shape, system.odometer) + with ui.card(): + ui.label('hold SHIFT to steer with the keyboard arrow keys or use the automation controls') + with ui.row(): + system.navigation.settings_ui() + with ui.row(): + automation_controls(system.automator) app.on_startup(startup) From e638b5b3ad9cca1adeb6d6e4d3f9869dfbfc80a1 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Fri, 23 Jan 2026 12:15:00 +0100 Subject: [PATCH 24/26] bring back drive segment todo --- feldfreund_devkit/navigation/drive_segment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/feldfreund_devkit/navigation/drive_segment.py b/feldfreund_devkit/navigation/drive_segment.py index 3272fb6..02670da 100644 --- a/feldfreund_devkit/navigation/drive_segment.py +++ b/feldfreund_devkit/navigation/drive_segment.py @@ -8,6 +8,7 @@ @dataclass(slots=True, kw_only=True) class DriveSegment(PathSegment): """A path segment with implement usage and stop behavior configuration.""" + # TODO: move methods to rosys.driving.PathSegment use_implement: bool = False stop_at_end: bool = True From 6d14cdf18a0df22eacc53a2072aff3759e522eb2 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Fri, 23 Jan 2026 16:07:47 +0100 Subject: [PATCH 25/26] update RoSys --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ca76cdb..8064362 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ readme = "README.md" requires-python = ">=3.11, <3.14" dependencies = [ "nicegui (>= 3.2.0, <4.0.0)", - "rosys @ git+https://github.com/zauberzeug/rosys.git@7f3954faeef1b3152096f32ff07e97f5c50c379c", + "rosys @ git+https://github.com/zauberzeug/rosys.git@bf941eb56ba2cc3254fa3b5c6c35cd54f173277a", "httpx >=0.25.0", "coloredlogs", "httpcore", From c195173fd9fbcfe8e49a8c7966b15df25852e250 Mon Sep 17 00:00:00 2001 From: Pascal Schade Date: Fri, 23 Jan 2026 16:07:56 +0100 Subject: [PATCH 26/26] add uv lock --- uv.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/uv.lock b/uv.lock index 897db58..189498a 100644 --- a/uv.lock +++ b/uv.lock @@ -640,7 +640,7 @@ requires-dist = [ { name = "httpx", specifier = ">=0.25.0" }, { name = "nicegui", specifier = ">=3.2.0,<4.0.0" }, { name = "psutil" }, - { name = "rosys", git = "https://github.com/zauberzeug/rosys.git?rev=7f3954faeef1b3152096f32ff07e97f5c50c379c" }, + { name = "rosys", git = "https://github.com/zauberzeug/rosys.git?rev=bf941eb56ba2cc3254fa3b5c6c35cd54f173277a" }, ] [package.metadata.requires-dev] @@ -1645,7 +1645,7 @@ wheels = [ [[package]] name = "nicegui" -version = "3.5.0" +version = "3.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiofiles" }, @@ -1670,9 +1670,9 @@ dependencies = [ { name = "uvicorn", extra = ["standard"] }, { name = "watchfiles" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2f/09/ace5c379c1bcd4e454fe01e32f14e4649456b5f60efb5f73c5737e8cd208/nicegui-3.5.0.tar.gz", hash = "sha256:de802505d76ac3235088b19a32dba0f15cf51caf0d5b0fa6e196bfa0bc247af6", size = 21177233, upload-time = "2026-01-08T09:18:26.646Z" } +sdist = { url = "https://files.pythonhosted.org/packages/59/de/82d966c6c84fc95847ceb9eb439eaf7087eb07bdc30c19903d6390de0901/nicegui-3.6.1.tar.gz", hash = "sha256:40f56f18f23023d03a15c217d62c0bf801e0c874745c7b5995c890ef01af3dfb", size = 21202754, upload-time = "2026-01-21T16:41:06.202Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/24/ff7ebfc2da4336687ba86813f96791dbd42e6d23a15301105d8353cc4652/nicegui-3.5.0-py3-none-any.whl", hash = "sha256:27d1659bbeeb543c96a9dad0c4da586896becbfec117bf8ed122a6e5b696340c", size = 21839035, upload-time = "2026-01-08T09:18:23.953Z" }, + { url = "https://files.pythonhosted.org/packages/1c/18/19539da813ab65c9d9fa08236fa891cddb5dfc55031fefaf475f50cd0aa6/nicegui-3.6.1-py3-none-any.whl", hash = "sha256:41c9ae11422ed3ac76f3d054dac600449e437a230c2a692d62cde847337f1548", size = 21865440, upload-time = "2026-01-21T16:41:02.926Z" }, ] [[package]] @@ -2431,8 +2431,8 @@ wheels = [ [[package]] name = "rosys" -version = "0.32.0.post4.dev0+7f3954fa" -source = { git = "https://github.com/zauberzeug/rosys.git?rev=7f3954faeef1b3152096f32ff07e97f5c50c379c#7f3954faeef1b3152096f32ff07e97f5c50c379c" } +version = "0.32.0.post5.dev0+bf941eb5" +source = { git = "https://github.com/zauberzeug/rosys.git?rev=bf941eb56ba2cc3254fa3b5c6c35cd54f173277a#bf941eb56ba2cc3254fa3b5c6c35cd54f173277a" } dependencies = [ { name = "aiohttp" }, { name = "cairosvg" },