psc-sr-robot3 2026.0.3.18__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. psc_sr_robot3-2026.0.3.18/.flake8 +14 -0
  2. psc_sr_robot3-2026.0.3.18/.github/dependabot.yml +34 -0
  3. psc_sr_robot3-2026.0.3.18/.github/workflows/test_build.yml +87 -0
  4. psc_sr_robot3-2026.0.3.18/.gitignore +135 -0
  5. psc_sr_robot3-2026.0.3.18/LICENSE +22 -0
  6. psc_sr_robot3-2026.0.3.18/Makefile +33 -0
  7. psc_sr_robot3-2026.0.3.18/PKG-INFO +195 -0
  8. psc_sr_robot3-2026.0.3.18/README.md +135 -0
  9. psc_sr_robot3-2026.0.3.18/firmware/arduino-fw/arduino-fw.ino +230 -0
  10. psc_sr_robot3-2026.0.3.18/psc_sr_robot3.egg-info/PKG-INFO +195 -0
  11. psc_sr_robot3-2026.0.3.18/psc_sr_robot3.egg-info/SOURCES.txt +86 -0
  12. psc_sr_robot3-2026.0.3.18/psc_sr_robot3.egg-info/dependency_links.txt +1 -0
  13. psc_sr_robot3-2026.0.3.18/psc_sr_robot3.egg-info/requires.txt +23 -0
  14. psc_sr_robot3-2026.0.3.18/psc_sr_robot3.egg-info/scm_file_list.json +82 -0
  15. psc_sr_robot3-2026.0.3.18/psc_sr_robot3.egg-info/scm_version.json +8 -0
  16. psc_sr_robot3-2026.0.3.18/psc_sr_robot3.egg-info/top_level.txt +1 -0
  17. psc_sr_robot3-2026.0.3.18/pyproject.toml +88 -0
  18. psc_sr_robot3-2026.0.3.18/setup.cfg +4 -0
  19. psc_sr_robot3-2026.0.3.18/sr/__init__.py +0 -0
  20. psc_sr_robot3-2026.0.3.18/sr/robot3/__init__.py +71 -0
  21. psc_sr_robot3-2026.0.3.18/sr/robot3/_version.py +24 -0
  22. psc_sr_robot3-2026.0.3.18/sr/robot3/arduino.py +734 -0
  23. psc_sr_robot3-2026.0.3.18/sr/robot3/astoria.py +303 -0
  24. psc_sr_robot3-2026.0.3.18/sr/robot3/battery.py +136 -0
  25. psc_sr_robot3-2026.0.3.18/sr/robot3/brain.py +405 -0
  26. psc_sr_robot3-2026.0.3.18/sr/robot3/bus_servo.py +446 -0
  27. psc_sr_robot3-2026.0.3.18/sr/robot3/buzzer.py +81 -0
  28. psc_sr_robot3-2026.0.3.18/sr/robot3/calibrations/__init__.py +4 -0
  29. psc_sr_robot3-2026.0.3.18/sr/robot3/camera.py +411 -0
  30. psc_sr_robot3-2026.0.3.18/sr/robot3/exceptions.py +55 -0
  31. psc_sr_robot3-2026.0.3.18/sr/robot3/game_specific.py +11 -0
  32. psc_sr_robot3-2026.0.3.18/sr/robot3/gamepad.py +714 -0
  33. psc_sr_robot3-2026.0.3.18/sr/robot3/i2c.py +687 -0
  34. psc_sr_robot3-2026.0.3.18/sr/robot3/kch.py +420 -0
  35. psc_sr_robot3-2026.0.3.18/sr/robot3/leds.py +87 -0
  36. psc_sr_robot3-2026.0.3.18/sr/robot3/logging.py +110 -0
  37. psc_sr_robot3-2026.0.3.18/sr/robot3/marker.py +157 -0
  38. psc_sr_robot3-2026.0.3.18/sr/robot3/motor_board.py +343 -0
  39. psc_sr_robot3-2026.0.3.18/sr/robot3/mqtt.py +223 -0
  40. psc_sr_robot3-2026.0.3.18/sr/robot3/pin_motors.py +238 -0
  41. psc_sr_robot3-2026.0.3.18/sr/robot3/power_board.py +578 -0
  42. psc_sr_robot3-2026.0.3.18/sr/robot3/py.typed +1 -0
  43. psc_sr_robot3-2026.0.3.18/sr/robot3/raw_serial.py +225 -0
  44. psc_sr_robot3-2026.0.3.18/sr/robot3/robot.py +630 -0
  45. psc_sr_robot3-2026.0.3.18/sr/robot3/serial_wrapper.py +262 -0
  46. psc_sr_robot3-2026.0.3.18/sr/robot3/servo_board.py +382 -0
  47. psc_sr_robot3-2026.0.3.18/sr/robot3/simulator/__init__.py +0 -0
  48. psc_sr_robot3-2026.0.3.18/sr/robot3/simulator/camera.py +78 -0
  49. psc_sr_robot3-2026.0.3.18/sr/robot3/simulator/time_server.py +94 -0
  50. psc_sr_robot3-2026.0.3.18/sr/robot3/timeout.py +85 -0
  51. psc_sr_robot3-2026.0.3.18/sr/robot3/utils.py +299 -0
  52. psc_sr_robot3-2026.0.3.18/stubs/RPi/GPIO.pyi +43 -0
  53. psc_sr_robot3-2026.0.3.18/stubs/RPi/__init__.pyi +0 -0
  54. psc_sr_robot3-2026.0.3.18/tests/__init__.py +1 -0
  55. psc_sr_robot3-2026.0.3.18/tests/conftest.py +97 -0
  56. psc_sr_robot3-2026.0.3.18/tests/test_arduino.py +355 -0
  57. psc_sr_robot3-2026.0.3.18/tests/test_battery.py +125 -0
  58. psc_sr_robot3-2026.0.3.18/tests/test_bus_servo.py +207 -0
  59. psc_sr_robot3-2026.0.3.18/tests/test_buzzer_pi.py +148 -0
  60. psc_sr_robot3-2026.0.3.18/tests/test_camera.py +180 -0
  61. psc_sr_robot3-2026.0.3.18/tests/test_data/bad/metadata.json +1 -0
  62. psc_sr_robot3-2026.0.3.18/tests/test_data/empty/.gitkeep +0 -0
  63. psc_sr_robot3-2026.0.3.18/tests/test_data/marker_detections.json +38 -0
  64. psc_sr_robot3-2026.0.3.18/tests/test_data/marker_locations.csv +37 -0
  65. psc_sr_robot3-2026.0.3.18/tests/test_data/missing_key/metadata.json +3 -0
  66. psc_sr_robot3-2026.0.3.18/tests/test_data/nested/valid/metadata.json +4 -0
  67. psc_sr_robot3-2026.0.3.18/tests/test_data/not_object/metadata.json +4 -0
  68. psc_sr_robot3-2026.0.3.18/tests/test_data/timeout_scripts/catch-base-exception.py +10 -0
  69. psc_sr_robot3-2026.0.3.18/tests/test_data/timeout_scripts/catch-exception.py +10 -0
  70. psc_sr_robot3-2026.0.3.18/tests/test_data/timeout_scripts/hot-loop.py +7 -0
  71. psc_sr_robot3-2026.0.3.18/tests/test_data/timeout_scripts/sleep.py +6 -0
  72. psc_sr_robot3-2026.0.3.18/tests/test_data/timeout_scripts/try-finally.py +11 -0
  73. psc_sr_robot3-2026.0.3.18/tests/test_data/timeout_scripts_extra/early-exit.py +3 -0
  74. psc_sr_robot3-2026.0.3.18/tests/test_data/timeout_scripts_extra/exception.py +5 -0
  75. psc_sr_robot3-2026.0.3.18/tests/test_data/valid/metadata.json +4 -0
  76. psc_sr_robot3-2026.0.3.18/tests/test_gamepad.py +336 -0
  77. psc_sr_robot3-2026.0.3.18/tests/test_i2c.py +762 -0
  78. psc_sr_robot3-2026.0.3.18/tests/test_leds.py +93 -0
  79. psc_sr_robot3-2026.0.3.18/tests/test_logging.py +42 -0
  80. psc_sr_robot3-2026.0.3.18/tests/test_markers.py +103 -0
  81. psc_sr_robot3-2026.0.3.18/tests/test_motor_board.py +294 -0
  82. psc_sr_robot3-2026.0.3.18/tests/test_pin_motors.py +250 -0
  83. psc_sr_robot3-2026.0.3.18/tests/test_power_board.py +425 -0
  84. psc_sr_robot3-2026.0.3.18/tests/test_raw_serial.py +151 -0
  85. psc_sr_robot3-2026.0.3.18/tests/test_serial_wrapper.py +173 -0
  86. psc_sr_robot3-2026.0.3.18/tests/test_servo_board.py +312 -0
  87. psc_sr_robot3-2026.0.3.18/tests/test_sr_robot.py +289 -0
  88. psc_sr_robot3-2026.0.3.18/tests/test_timeout.py +99 -0
@@ -0,0 +1,14 @@
1
+ [flake8]
2
+ max_line_length = 95
3
+ ignore =
4
+ # Don't require imperative mood docstrings.
5
+ D401,
6
+ # Ignore docstrings on magic methods
7
+ D105,
8
+ # Ignore docstrings on init methods
9
+ D107,
10
+ # Allow line breaks before and after a binary operator
11
+ W503, W504,
12
+ # Ignore TODO comments
13
+ T000,
14
+
@@ -0,0 +1,34 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: pip
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ open-pull-requests-limit: 10
8
+ ignore:
9
+ - dependency-name: sphinx
10
+ versions:
11
+ - 3.4.3
12
+ - 3.5.0
13
+ - 3.5.1
14
+ - 3.5.2
15
+ - 3.5.3
16
+ - dependency-name: flake8
17
+ versions:
18
+ - 3.8.4
19
+ - 3.9.0
20
+ - dependency-name: pytest
21
+ versions:
22
+ - 6.2.2
23
+ - dependency-name: sphinx-rtd-theme
24
+ versions:
25
+ - 0.5.1
26
+ - dependency-name: isort
27
+ versions:
28
+ - 5.7.0
29
+ - dependency-name: flake8-comprehensions
30
+ versions:
31
+ - 3.3.1
32
+ - dependency-name: rope
33
+ versions:
34
+ - 0.18.0
@@ -0,0 +1,87 @@
1
+ name: Lint & build
2
+
3
+ on:
4
+ push:
5
+ workflow_dispatch:
6
+
7
+ jobs:
8
+ test:
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ os: [ubuntu-latest]
13
+ py_version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14
+ include:
15
+ - os: windows-latest
16
+ py_version: "3.9"
17
+ - os: windows-latest
18
+ py_version: "3.13"
19
+ - os: macos-latest
20
+ py_version: "3.9"
21
+ - os: macos-latest
22
+ py_version: "3.13"
23
+ runs-on: ${{ matrix.os }}
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ with:
27
+ fetch-depth: 0
28
+ - name: Set up Python
29
+ uses: actions/setup-python@v5
30
+ with:
31
+ python-version: ${{ matrix.py_version }}
32
+ - name: Install dependencies
33
+ run: |
34
+ python -m pip install --upgrade pip
35
+ python -m pip install .[dev,vision]
36
+ - name: Lint
37
+ run: |
38
+ make lint
39
+ - name: Isort
40
+ run: |
41
+ make isort-check
42
+ - name: Typecheck
43
+ run: |
44
+ make type
45
+ - name: Run tests
46
+ run: |
47
+ make test
48
+
49
+ build:
50
+ permissions:
51
+ id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
52
+ runs-on: ubuntu-latest
53
+ needs: test
54
+ # PyPI's trusted publisher for psc-sr-robot3 names this environment
55
+ environment:
56
+ name: pypi
57
+ url: https://pypi.org/p/psc-sr-robot3
58
+ steps:
59
+ - uses: actions/checkout@v4
60
+ with:
61
+ fetch-depth: 0
62
+ - name: Set up Python 3.10
63
+ uses: actions/setup-python@v5
64
+ with:
65
+ python-version: "3.10"
66
+ - name: Install dependencies
67
+ run: |
68
+ python -m pip install --upgrade pip build
69
+ # Install package to generate version info
70
+ python -m pip install .
71
+ - name: Build package
72
+ run: |
73
+ make build
74
+ - name: Save built package
75
+ uses: actions/upload-artifact@v4
76
+ with:
77
+ name: package
78
+ path: |
79
+ dist
80
+ - name: Check the package
81
+ run: |
82
+ python -m pip install twine
83
+ python -m twine check --strict dist/*
84
+ - name: Publish to PyPi
85
+ # Version tags only, such as 2026.0.3.18
86
+ if: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, '20') }}
87
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,135 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
90
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
91
+ # install all needed dependencies.
92
+ #Pipfile.lock
93
+
94
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95
+ __pypackages__/
96
+
97
+ # Celery stuff
98
+ celerybeat-schedule
99
+ celerybeat.pid
100
+
101
+ # SageMath parsed files
102
+ *.sage.py
103
+
104
+ # Environments
105
+ .env
106
+ .venv
107
+ env/
108
+ venv/
109
+ ENV/
110
+ env.bak/
111
+ venv.bak/
112
+
113
+ # Spyder project settings
114
+ .spyderproject
115
+ .spyproject
116
+
117
+ # Rope project settings
118
+ .ropeproject
119
+
120
+ # mkdocs documentation
121
+ /site
122
+
123
+ # mypy
124
+ .mypy_cache/
125
+ .dmypy.json
126
+ dmypy.json
127
+
128
+ # Pyre type checker
129
+ .pyre/
130
+
131
+ _version.py
132
+
133
+ # macOS metadata
134
+ .DS_Store
135
+ **/.DS_Store
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019-21 Dan Trickey
4
+ Copyright (c) 2023 SourceBots
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,33 @@
1
+ .PHONY: lint type test test-html isort isort-check build upload
2
+
3
+ PYMODULE:=sr/robot3
4
+ TESTS:=tests
5
+
6
+ all: lint isort-check type test
7
+
8
+ lint:
9
+ flake8 $(PYMODULE)
10
+
11
+ type:
12
+ mypy $(PYMODULE)
13
+
14
+ test:
15
+ pytest --cov=$(PYMODULE) --cov-report=term --cov-report=xml $(TESTS)
16
+
17
+ test-html:
18
+ pytest --cov=$(PYMODULE) --cov-report=html $(TESTS)
19
+
20
+ isort-check:
21
+ python -m isort --check $(PYMODULE)
22
+
23
+ isort:
24
+ python -m isort $(PYMODULE)
25
+
26
+ build:
27
+ python -m build
28
+
29
+ upload:
30
+ twine upload dist/*
31
+
32
+ clean:
33
+ rm -rf dist/* build/*
@@ -0,0 +1,195 @@
1
+ Metadata-Version: 2.4
2
+ Name: psc-sr-robot3
3
+ Version: 2026.0.3.18
4
+ Summary: PSC Robotics' version of the Student Robotics API for Python 3
5
+ Author: PSC Robotics
6
+ Author-email: Student Robotics <kit-team@studentrobotics.org>
7
+ License: MIT License
8
+
9
+ Copyright (c) 2019-21 Dan Trickey
10
+ Copyright (c) 2023 SourceBots
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+
30
+ Project-URL: Repository, https://github.com/PSC-Robotics/Custom-SR-Library
31
+ Project-URL: Homepage, https://psc-robotics.uk
32
+ Project-URL: Documentation, https://docs.psc-robotics.uk
33
+ Project-URL: Student Robotics sr-robot3, https://github.com/srobo/sr-robot
34
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
35
+ Classifier: Operating System :: OS Independent
36
+ Classifier: Development Status :: 5 - Production/Stable
37
+ Classifier: Typing :: Typed
38
+ Classifier: Topic :: Education
39
+ Requires-Python: >=3.9
40
+ Description-Content-Type: text/markdown
41
+ License-File: LICENSE
42
+ Requires-Dist: pyserial<4,>=3
43
+ Requires-Dist: april_vision==3.0.0
44
+ Requires-Dist: paho-mqtt<3,>=2
45
+ Requires-Dist: pydantic<2,>=1.9.1
46
+ Requires-Dist: typing-extensions; python_version < "3.10"
47
+ Requires-Dist: tomli<3,>=2.0.1; python_version < "3.11"
48
+ Provides-Extra: dev
49
+ Requires-Dist: flake8; extra == "dev"
50
+ Requires-Dist: isort; extra == "dev"
51
+ Requires-Dist: mypy<2,>=1.7; extra == "dev"
52
+ Requires-Dist: build; extra == "dev"
53
+ Requires-Dist: types-pyserial; extra == "dev"
54
+ Requires-Dist: pytest; extra == "dev"
55
+ Requires-Dist: pytest-cov; extra == "dev"
56
+ Requires-Dist: paho-mqtt<3,>=2; extra == "dev"
57
+ Provides-Extra: vision
58
+ Requires-Dist: opencv-python-headless<5,>=4.10; extra == "vision"
59
+ Dynamic: license-file
60
+
61
+ # psc-sr-robot3
62
+
63
+ [![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://opensource.org/licenses/MIT)
64
+
65
+ `psc-sr-robot3` is PSC Robotics' version of [sr-robot3](https://github.com/srobo/sr-robot),
66
+ the Student Robotics Python API. It adds PSC's brain board: GPIO motors and steppers,
67
+ servo drivers and I2C, the brain board LED and battery sensor, the buzzer and gamepads.
68
+ See the [PSC Robotics docs](https://docs.psc-robotics.uk).
69
+
70
+ Your code imports it as `sr.robot3`, the same as Student Robotics' library, so the two
71
+ can't be installed together. The PSC Robotics OS image already has it installed; install
72
+ it on a computer to get code completion and type checking while you write robot code.
73
+
74
+ ## Installation
75
+
76
+ ```bash
77
+ pip install psc-sr-robot3
78
+ ```
79
+
80
+ To include OpenCV, for the camera:
81
+
82
+ ```bash
83
+ pip install "psc-sr-robot3[vision]"
84
+ ```
85
+
86
+ Versions are Student Robotics' base version followed by PSC's own release number:
87
+ 2026.0.3.18 is PSC release 18 of sr-robot3 2026.0.3.
88
+
89
+ ## Usage
90
+
91
+ The main entry point for the API is the `Robot` class.
92
+ Instantiating this class will automatically detect and connect to any supported SR v4 boards connected to the device.
93
+ All SR boards are optional; connected boards are initialized and exposed as usual. By default, the `Robot` class waits for a start signal before continuing. When a power board is present, its start button is used; without one, the start signal can come from Astoria.
94
+
95
+ ```python
96
+
97
+ from sr.robot3 import Robot
98
+
99
+ r = Robot()
100
+
101
+ ```
102
+
103
+ To disable the waiting for the start button, you can pass `wait_for_start=False` to the constructor.
104
+ The `wait_for_start` method needs to be called before the metadata is available.
105
+
106
+ ```python
107
+
108
+ from sr.robot3 import Robot
109
+
110
+ r = Robot(wait_for_start=False)
111
+
112
+ # Setup in here
113
+
114
+ r.wait_start()
115
+
116
+ ```
117
+
118
+ An Arduino running firmware version 4 or later can drive a step/direction
119
+ stepper driver with `arduino.stepper_move(step_pin, direction_pin, steps)`. The
120
+ call blocks until the requested pulses are emitted; pass `direction=False` to
121
+ drive DIR low, and use `step_delay_us` to set the low interval between pulses.
122
+ Moves are limited to 350 ms per command so they fit within the serial timeout.
123
+ This API does not provide acceleration or track motor position.
124
+
125
+ ### Buzzer
126
+
127
+ `robot.buzzer.buzz(frequency, duration, blocking=False)` plays a tone on the
128
+ buzzer connected to the brain board, like the Student Robotics power board's
129
+ `piezo.buzz()`. `Note` values such as `Note.A6` can be used for the frequency.
130
+ A new tone replaces the one playing. Tones are played by the robot's status
131
+ service, which also beeps when code is waiting for the start button, when start
132
+ is pressed, and with fast short beeps when code crashes.
133
+
134
+ ### Steppers on the brain board's GPIO pins
135
+
136
+ `robot.brain.stepper_move(step_pin, direction_pin, steps)` drives a
137
+ step/direction stepper driver wired to the Pi's GPIO header, using BCM GPIO
138
+ numbers. It takes the same arguments as `arduino.stepper_move`, but has no
139
+ 350 ms limit: `steps` can be up to 1000000 and `step_delay_us` from 50 to
140
+ 1000000. Timing is done in software, so step timing can vary slightly. GPIO 5,
141
+ 13 and 18 are used by the robot and can't be used.
142
+
143
+ ### Multiple cameras
144
+
145
+ Every connected camera with a calibration is available in `robot.cameras`.
146
+ `robot.camera` still works when exactly one camera is connected.
147
+
148
+ ```python
149
+ from sr.robot3 import Robot
150
+
151
+ r = Robot()
152
+
153
+ for camera_id, camera in r.cameras.items():
154
+ print(camera_id, camera.see())
155
+
156
+ front = r.cameras["A1B2C3D4"]
157
+ ```
158
+
159
+ Cameras are keyed by their USB serial number. Cameras with no serial number,
160
+ a generic placeholder serial or a serial shared with another connected camera
161
+ are keyed by the USB port they are plugged into, such as `usb-1-1.2`. Keep
162
+ those cameras in the same ports so their names stay the same. The camera
163
+ calibration dialog in the robot web UI shows the name of each connected camera.
164
+ Cameras of the same model share one calibration.
165
+
166
+ ### Camera calibrations
167
+
168
+ The bundled Logitech calibrations are used automatically and are read-only in
169
+ the camera calibration dialog. Custom calibration directories can be added to the code
170
+ USB root with either `camera-calibrations.toml`:
171
+
172
+ ```toml
173
+ calibrations = ["camera-calibrations"]
174
+ ```
175
+
176
+ or `camera-calibrations.json`:
177
+
178
+ ```json
179
+ {"calibrations": ["camera-calibrations"]}
180
+ ```
181
+
182
+ Place the AprilVision calibration XML files in the listed directory. Paths are
183
+ relative to the manifest and must remain on the code USB. Only cameras matching
184
+ a loaded calibration are added to `Robot.cameras`.
185
+
186
+ ## Developer Notes
187
+
188
+ There are a number of considerations that have been made in the design of this API.
189
+ Some of these may not be immediately obvious, so they are documented below.
190
+
191
+ - The API is designed to raise exceptions for incorrect actions, such as trying to modify the output dictionary or assign a value directly to the motor object.
192
+ - `MappingProxyType` is used to prevent the user from adding, removing or overwriting keys in any parts of the API that return a dictionary.
193
+ - `tuple` is used to prevent the user from adding, removing or overwriting items in any parts of the API that would return a list.
194
+ - `__slots__` is used to prevent the user from adding, removing or overwriting attributes in any parts of the API.
195
+ - `sr.robot3.serial_wrapper.SerialWrapper` handles automatic reconnection to the serial port if the connection is lost and impleents 3 retries on any serial operation before raising a `BoardDisconnectionError`.
@@ -0,0 +1,135 @@
1
+ # psc-sr-robot3
2
+
3
+ [![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://opensource.org/licenses/MIT)
4
+
5
+ `psc-sr-robot3` is PSC Robotics' version of [sr-robot3](https://github.com/srobo/sr-robot),
6
+ the Student Robotics Python API. It adds PSC's brain board: GPIO motors and steppers,
7
+ servo drivers and I2C, the brain board LED and battery sensor, the buzzer and gamepads.
8
+ See the [PSC Robotics docs](https://docs.psc-robotics.uk).
9
+
10
+ Your code imports it as `sr.robot3`, the same as Student Robotics' library, so the two
11
+ can't be installed together. The PSC Robotics OS image already has it installed; install
12
+ it on a computer to get code completion and type checking while you write robot code.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install psc-sr-robot3
18
+ ```
19
+
20
+ To include OpenCV, for the camera:
21
+
22
+ ```bash
23
+ pip install "psc-sr-robot3[vision]"
24
+ ```
25
+
26
+ Versions are Student Robotics' base version followed by PSC's own release number:
27
+ 2026.0.3.18 is PSC release 18 of sr-robot3 2026.0.3.
28
+
29
+ ## Usage
30
+
31
+ The main entry point for the API is the `Robot` class.
32
+ Instantiating this class will automatically detect and connect to any supported SR v4 boards connected to the device.
33
+ All SR boards are optional; connected boards are initialized and exposed as usual. By default, the `Robot` class waits for a start signal before continuing. When a power board is present, its start button is used; without one, the start signal can come from Astoria.
34
+
35
+ ```python
36
+
37
+ from sr.robot3 import Robot
38
+
39
+ r = Robot()
40
+
41
+ ```
42
+
43
+ To disable the waiting for the start button, you can pass `wait_for_start=False` to the constructor.
44
+ The `wait_for_start` method needs to be called before the metadata is available.
45
+
46
+ ```python
47
+
48
+ from sr.robot3 import Robot
49
+
50
+ r = Robot(wait_for_start=False)
51
+
52
+ # Setup in here
53
+
54
+ r.wait_start()
55
+
56
+ ```
57
+
58
+ An Arduino running firmware version 4 or later can drive a step/direction
59
+ stepper driver with `arduino.stepper_move(step_pin, direction_pin, steps)`. The
60
+ call blocks until the requested pulses are emitted; pass `direction=False` to
61
+ drive DIR low, and use `step_delay_us` to set the low interval between pulses.
62
+ Moves are limited to 350 ms per command so they fit within the serial timeout.
63
+ This API does not provide acceleration or track motor position.
64
+
65
+ ### Buzzer
66
+
67
+ `robot.buzzer.buzz(frequency, duration, blocking=False)` plays a tone on the
68
+ buzzer connected to the brain board, like the Student Robotics power board's
69
+ `piezo.buzz()`. `Note` values such as `Note.A6` can be used for the frequency.
70
+ A new tone replaces the one playing. Tones are played by the robot's status
71
+ service, which also beeps when code is waiting for the start button, when start
72
+ is pressed, and with fast short beeps when code crashes.
73
+
74
+ ### Steppers on the brain board's GPIO pins
75
+
76
+ `robot.brain.stepper_move(step_pin, direction_pin, steps)` drives a
77
+ step/direction stepper driver wired to the Pi's GPIO header, using BCM GPIO
78
+ numbers. It takes the same arguments as `arduino.stepper_move`, but has no
79
+ 350 ms limit: `steps` can be up to 1000000 and `step_delay_us` from 50 to
80
+ 1000000. Timing is done in software, so step timing can vary slightly. GPIO 5,
81
+ 13 and 18 are used by the robot and can't be used.
82
+
83
+ ### Multiple cameras
84
+
85
+ Every connected camera with a calibration is available in `robot.cameras`.
86
+ `robot.camera` still works when exactly one camera is connected.
87
+
88
+ ```python
89
+ from sr.robot3 import Robot
90
+
91
+ r = Robot()
92
+
93
+ for camera_id, camera in r.cameras.items():
94
+ print(camera_id, camera.see())
95
+
96
+ front = r.cameras["A1B2C3D4"]
97
+ ```
98
+
99
+ Cameras are keyed by their USB serial number. Cameras with no serial number,
100
+ a generic placeholder serial or a serial shared with another connected camera
101
+ are keyed by the USB port they are plugged into, such as `usb-1-1.2`. Keep
102
+ those cameras in the same ports so their names stay the same. The camera
103
+ calibration dialog in the robot web UI shows the name of each connected camera.
104
+ Cameras of the same model share one calibration.
105
+
106
+ ### Camera calibrations
107
+
108
+ The bundled Logitech calibrations are used automatically and are read-only in
109
+ the camera calibration dialog. Custom calibration directories can be added to the code
110
+ USB root with either `camera-calibrations.toml`:
111
+
112
+ ```toml
113
+ calibrations = ["camera-calibrations"]
114
+ ```
115
+
116
+ or `camera-calibrations.json`:
117
+
118
+ ```json
119
+ {"calibrations": ["camera-calibrations"]}
120
+ ```
121
+
122
+ Place the AprilVision calibration XML files in the listed directory. Paths are
123
+ relative to the manifest and must remain on the code USB. Only cameras matching
124
+ a loaded calibration are added to `Robot.cameras`.
125
+
126
+ ## Developer Notes
127
+
128
+ There are a number of considerations that have been made in the design of this API.
129
+ Some of these may not be immediately obvious, so they are documented below.
130
+
131
+ - The API is designed to raise exceptions for incorrect actions, such as trying to modify the output dictionary or assign a value directly to the motor object.
132
+ - `MappingProxyType` is used to prevent the user from adding, removing or overwriting keys in any parts of the API that return a dictionary.
133
+ - `tuple` is used to prevent the user from adding, removing or overwriting items in any parts of the API that would return a list.
134
+ - `__slots__` is used to prevent the user from adding, removing or overwriting attributes in any parts of the API.
135
+ - `sr.robot3.serial_wrapper.SerialWrapper` handles automatic reconnection to the serial port if the connection is lost and impleents 3 retries on any serial operation before raising a `BoardDisconnectionError`.