pybricks 3.2.0rc2__tar.gz → 3.3.0a5__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 (39) hide show
  1. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/PKG-INFO +6 -1
  2. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/README.rst +5 -0
  3. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/pyproject.toml +4 -2
  4. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/_common.py +266 -22
  5. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/ev3devices.py +2 -4
  6. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/hubs.py +100 -9
  7. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/parameters.py +15 -1
  8. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/pupdevices.py +8 -3
  9. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/robotics.py +18 -9
  10. pybricks-3.3.0a5/src/pybricks/tools.py +227 -0
  11. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/urandom/__init__.py +1 -1
  12. pybricks-3.2.0rc2/setup.py +0 -50
  13. pybricks-3.2.0rc2/src/pybricks/geometry.py +0 -132
  14. pybricks-3.2.0rc2/src/pybricks/tools.py +0 -102
  15. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/LICENSE +0 -0
  16. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/micropython/__init__.py +0 -0
  17. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/micropython/py.typed +0 -0
  18. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/__init__.py +0 -0
  19. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/ev3dev/_speaker.py +0 -0
  20. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/iodevices.py +0 -0
  21. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/media/__init__.py +0 -0
  22. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/media/ev3dev.py +0 -0
  23. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/media/py.typed +0 -0
  24. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/messaging.py +0 -0
  25. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/nxtdevices.py +0 -0
  26. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/pybricks/py.typed +0 -0
  27. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/uerrno/__init__.py +0 -0
  28. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/uerrno/py.typed +0 -0
  29. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/uio/__init__.py +0 -0
  30. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/uio/py.typed +0 -0
  31. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/ujson/__init__.py +0 -0
  32. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/umath/__init__.py +0 -0
  33. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/umath/py.typed +0 -0
  34. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/urandom/py.typed +0 -0
  35. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/uselect/__init__.py +0 -0
  36. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/uselect/py.typed +0 -0
  37. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/ustruct/__init__.py +0 -0
  38. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/usys/__init__.py +0 -0
  39. {pybricks-3.2.0rc2 → pybricks-3.3.0a5}/src/usys/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pybricks
3
- Version: 3.2.0rc2
3
+ Version: 3.3.0a5
4
4
  Summary: Documentation and user-API stubs for Pybricks MicroPython
5
5
  Home-page: https://pybricks.com
6
6
  License: MIT
@@ -35,6 +35,11 @@ used to generate the `official documentation`_.
35
35
  See the `contributor's guide <CONTRIBUTING.md>`_ for acceptable changes and
36
36
  instructions to build the documentation locally.
37
37
 
38
+ You can use the API stubs in this repository for syntax highlighting and code
39
+ completion when programming the EV3 with VS Code. To enable, remove the
40
+ ``"python.languageServer"="None"`` line in the ``.vscode/settings.json`` file
41
+ generated by the *LEGO® MINDSTORMS® EV3 MicroPython* extension.
42
+
38
43
  For general discussion, please visit the `support`_ issue tracker.
39
44
 
40
45
  .. _Pybricks package: pybricks
@@ -12,6 +12,11 @@ used to generate the `official documentation`_.
12
12
  See the `contributor's guide <CONTRIBUTING.md>`_ for acceptable changes and
13
13
  instructions to build the documentation locally.
14
14
 
15
+ You can use the API stubs in this repository for syntax highlighting and code
16
+ completion when programming the EV3 with VS Code. To enable, remove the
17
+ ``"python.languageServer"="None"`` line in the ``.vscode/settings.json`` file
18
+ generated by the *LEGO® MINDSTORMS® EV3 MicroPython* extension.
19
+
15
20
  For general discussion, please visit the `support`_ issue tracker.
16
21
 
17
22
  .. _Pybricks package: pybricks
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pybricks"
3
- version = "3.2.0c2"
3
+ version = "3.3.0a5"
4
4
  description = "Documentation and user-API stubs for Pybricks MicroPython"
5
5
  authors = ["The Pybricks Authors <dev@pybricks.com>"]
6
6
  maintainers = ["Laurens Valk <laurens@pybricks.com>", "David Lechner <david@pybricks.com>" ]
@@ -29,10 +29,12 @@ packages = [
29
29
  [tool.poetry.dependencies]
30
30
  python = "^3.8"
31
31
 
32
- [tool.poetry.dev-dependencies]
32
+ [tool.poetry.group.lint.dependencies]
33
33
  black = "^22.3.0"
34
34
  doc8 = "^0.8.1"
35
35
  flake8 = "^4.0"
36
+
37
+ [tool.poetry.group.doc.dependencies]
36
38
  Sphinx = { git = "https://github.com/pybricks/sphinx.git", rev = "b00124cb" }
37
39
  sphinx-rtd-theme = "^1.0.0"
38
40
  toml = "^0.10.0"
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2018-2021 The Pybricks Authors
2
+ # Copyright (c) 2018-2023 The Pybricks Authors
3
3
 
4
4
  """Generic cross-platform module for typical devices like lights, displays,
5
5
  speakers, and batteries."""
@@ -8,8 +8,8 @@ from __future__ import annotations
8
8
 
9
9
  from typing import Union, Iterable, overload, Optional, Tuple, Collection, TYPE_CHECKING
10
10
 
11
- from .geometry import Matrix, Axis
12
- from .parameters import Direction, Stop, Button, Port, Color, Side
11
+ from .tools import Matrix
12
+ from .parameters import Axis, Direction, Stop, Button, Port, Color, Side
13
13
 
14
14
  if TYPE_CHECKING:
15
15
  from .parameters import Number
@@ -219,18 +219,18 @@ class Control:
219
219
  kp: Optional[Number] = None,
220
220
  ki: Optional[Number] = None,
221
221
  kd: Optional[Number] = None,
222
- reserved: Optional[Number] = None,
222
+ integral_deadzone: Optional[Number] = None,
223
223
  integral_rate: Optional[Number] = None,
224
224
  ) -> None:
225
225
  ...
226
226
 
227
227
  @overload
228
- def pid(self) -> Tuple[int, int, int, None, int]:
228
+ def pid(self) -> Tuple[int, int, int, int, int]:
229
229
  ...
230
230
 
231
231
  def pid(self, *args):
232
- """pid(kp, ki, kd, reserved, integral_rate)
233
- pid() -> Tuple[int, int, int, None, int]
232
+ """pid(kp, ki, kd, integral_deadzone, integral_rate)
233
+ pid() -> Tuple[int, int, int, int, int]
234
234
 
235
235
  Gets or sets the PID values for position and speed control.
236
236
 
@@ -245,7 +245,8 @@ class Control:
245
245
  kd (int): Derivative position (or proportional speed) control
246
246
  constant. It is the feedback torque per
247
247
  unit of speed: µNm/(deg/s).
248
- reserved: This setting is not used.
248
+ integral_deadzone (Number, deg or Number, mm): Zone around the
249
+ target where the error integral does not accumulate errors.
249
250
  integral_rate (Number, deg/s or Number, mm/s): Maximum rate at
250
251
  which the error integral is allowed to grow.
251
252
  """
@@ -303,6 +304,52 @@ class Control:
303
304
  """
304
305
 
305
306
 
307
+ class Model:
308
+ """Class to interact with motor state observer and settings."""
309
+
310
+ def state(self) -> Tuple[float, float, float, bool]:
311
+ """state() -> Tuple[float, float, float, bool]
312
+
313
+ Gets the estimated angle, speed, current, and stall state of the motor,
314
+ using a simulation model that mimics the real motor.
315
+ These estimates are updated faster than the real measurements,
316
+ which can be useful when building your own PID controllers.
317
+
318
+ For most applications it is better to used the *measured*
319
+ :meth:`angle <pybricks.pupdevices.Motor.angle>`,
320
+ :meth:`speed <pybricks.pupdevices.Motor.speed>`,
321
+ :meth:`load <pybricks.pupdevices.Motor.load>`, and
322
+ :meth:`stall <pybricks.pupdevices.Motor.stalled>` state instead.
323
+
324
+ Returns:
325
+ Tuple with the estimated angle (deg), speed (deg/s), current (mA),
326
+ and stall state (``True`` or ``False``).
327
+ """
328
+
329
+ @overload
330
+ def settings(self, values: tuple) -> None:
331
+ ...
332
+
333
+ @overload
334
+ def settings(self) -> tuple:
335
+ ...
336
+
337
+ def settings(self, speed, time):
338
+ """settings(values)
339
+ settings() -> Tuple
340
+
341
+ Gets or sets model settings as a tuple of integers. If no arguments are
342
+ given, this will return the current values. This method is mainly used
343
+ to debug the motor model class. Changing these settings should not be
344
+ needed in user programs.
345
+
346
+ .. _model settings: https://docs.pybricks.com/projects/pbio/en/latest/struct__pbio__observer__settings__t.html
347
+
348
+ Arguments:
349
+ values (Tuple): Tuple with `model settings`_.
350
+ """
351
+
352
+
306
353
  class Motor(DCMotor):
307
354
  """Generic class to control motors with built-in rotation sensors."""
308
355
 
@@ -312,14 +359,18 @@ class Motor(DCMotor):
312
359
  ``control`` attribute of the motor. See :ref:`control` for an overview
313
360
  of available methods."""
314
361
 
362
+ model = Model()
363
+ """Model representing the observer that estimates the motor state."""
364
+
315
365
  def __init__(
316
366
  self,
317
367
  port: Port,
318
368
  positive_direction: Direction = Direction.CLOCKWISE,
319
369
  gears: Optional[Union[Collection[int], Collection[Collection[int]]]] = None,
320
370
  reset_angle: bool = True,
371
+ profile: Number = None,
321
372
  ):
322
- """__init__(port, positive_direction=Direction.CLOCKWISE, gears=None, reset_angle=True)
373
+ """__init__(port, positive_direction=Direction.CLOCKWISE, gears=None, reset_angle=True, profile=None)
323
374
 
324
375
  Arguments:
325
376
  port (Port): Port to which the motor is connected.
@@ -336,12 +387,16 @@ class Motor(DCMotor):
336
387
  When you specify a gear train, all motor commands and settings
337
388
  are automatically adjusted to account for the resulting gear
338
389
  ratio. The motor direction remains unchanged by this.
339
- reset_angle(bool):
390
+ reset_angle (bool):
340
391
  Choose ``True`` to reset the rotation sensor value to the
341
392
  absolute marker angle (between -180 and 179).
342
393
  Choose ``False`` to keep the
343
394
  current value, so your program knows where it left off last
344
395
  time.
396
+ profile (Number, deg): Precision profile. A lower value
397
+ means more precise movement; a larger value means
398
+ smoother movement. If no value is given, a suitable profile for
399
+ this motor type will be selected automatically.
345
400
  """
346
401
 
347
402
  def angle(self) -> int:
@@ -353,11 +408,19 @@ class Motor(DCMotor):
353
408
  Motor angle.
354
409
  """
355
410
 
356
- def speed(self) -> int:
357
- """speed() -> int: deg/s
411
+ def speed(self, window: Number = 100) -> int:
412
+ """speed(window=100) -> int: deg/s
358
413
 
359
414
  Gets the speed of the motor.
360
415
 
416
+ The speed is measured as the change in the motor angle during the
417
+ given time window. A short window makes the speed value more
418
+ responsive to motor movement, but less steady. A long window makes the
419
+ speed value less responsive, but more steady.
420
+
421
+ Arguments:
422
+ window (Number, ms): The time window used to determine the speed.
423
+
361
424
  Returns:
362
425
  Motor speed.
363
426
 
@@ -731,7 +794,7 @@ class LightMatrix:
731
794
 
732
795
  Arguments:
733
796
  matrices (iter): Sequence of
734
- :class:`Matrix <pybricks.geometry.Matrix>` of intensities.
797
+ :class:`Matrix <pybricks.tools.Matrix>` of intensities.
735
798
  interval (Number, ms): Time to display each image in the list.
736
799
  """
737
800
 
@@ -928,22 +991,94 @@ class Accelerometer(SimpleAccelerometer):
928
991
  along the x-axis.
929
992
 
930
993
  Returns:
931
- Tuple of pitch and roll angles.
994
+ Tuple of pitch and roll angles in degrees.
932
995
  """
933
996
 
934
997
 
935
998
  class IMU(Accelerometer):
999
+ def ready(self) -> bool:
1000
+ """ready() -> bool
1001
+
1002
+ Checks if the device is calibrated and ready for use.
1003
+
1004
+ This becomes ``True`` when the robot has been sitting stationary for a
1005
+ few seconds, which allows the device to re-calibrate. It is ``False``
1006
+ if the hub has just been started, or if it hasn't had a chance to
1007
+ calibrate for more than 10 minutes.
1008
+
1009
+ Returns:
1010
+ ``True`` if it is ready for use, ``False`` if not.
1011
+ """
1012
+
1013
+ def stationary(self) -> bool:
1014
+ """stationary() -> bool
1015
+
1016
+ Checks if the device is currently stationary (not moving).
1017
+
1018
+ Returns:
1019
+ ``True`` if stationary for at least a second, ``False`` if it is
1020
+ moving.
1021
+ """
1022
+
1023
+ @overload
1024
+ def settings(
1025
+ self,
1026
+ angular_velocity_threshold: float = None,
1027
+ acceleration_threshold: float = None,
1028
+ ) -> None:
1029
+ ...
1030
+
1031
+ @overload
1032
+ def settings(self) -> Tuple[float, float]:
1033
+ ...
1034
+
1035
+ def settings(self, *args):
1036
+ """
1037
+ settings(angular_velocity_threshold, acceleration_threshold)
1038
+ settings() -> Tuple[float, float]
1039
+
1040
+ Configures the IMU settings. If no arguments are given,
1041
+ this returns the current values.
1042
+
1043
+ The ``angular_velocity_threshold`` and ``acceleration_threshold``
1044
+ define when the hub is considered stationary. If all
1045
+ measurements stay below these thresholds for one second, the IMU
1046
+ will recalibrate itself.
1047
+
1048
+ In a noisy room with high ambient vibrations (such as a
1049
+ competition hall), it is recommended to increase the thresholds
1050
+ slightly to give your robot the chance to calibrate.
1051
+ To verify that your settings are working as expected, test that
1052
+ the ``stationary()`` method gives ``False`` if your robot is moving,
1053
+ and ``True`` if it is sitting still for at least a second.
1054
+
1055
+ Arguments:
1056
+ angular_velocity_threshold (Number, deg/s): The threshold for
1057
+ angular velocity. The default value is 1.5 deg/s.
1058
+ acceleration_threshold (Number, mm/s²): The threshold for angular
1059
+ velocity. The default value is 250 mm/s².
1060
+ """
1061
+
936
1062
  def heading(self) -> float:
937
1063
  """heading() -> float: deg
938
1064
 
939
- Gets the heading angle relative to the starting orientation. It is a
940
- positive rotation around the :ref:`z-axis in the robot
941
- frame <robotframe>`, prior to applying any tilt rotation.
1065
+ Gets the heading angle of your robot. A positive value means a
1066
+ clockwise turn.
942
1067
 
943
- For a vehicle viewed from the top, this means that
944
- a positive heading value corresponds to a counterclockwise rotation.
1068
+ The heading is 0 when your program starts. The value continues to grow
1069
+ even as the robot turns more than 180 degrees. It does not wrap around
1070
+ to -180 like it does in some apps.
945
1071
 
946
- .. note:: This method is not yet implemented.
1072
+
1073
+ .. note:: *For now, this method only keeps track of the heading while
1074
+ the robot is on a flat surface.*
1075
+
1076
+ This means that the value is
1077
+ no longer correct if you lift it from the table. To solve
1078
+ this, you can call ``reset_heading`` to reset the heading to
1079
+ a known value *after* you put it back down. For example, you
1080
+ could align your robot with the side of the competition table
1081
+ and reset the heading 90 degrees as the new starting point.
947
1082
 
948
1083
  Returns:
949
1084
  Heading angle relative to starting orientation.
@@ -955,8 +1090,6 @@ class IMU(Accelerometer):
955
1090
 
956
1091
  Resets the accumulated heading angle of the robot.
957
1092
 
958
- .. note:: This method is not yet implemented.
959
-
960
1093
  Arguments:
961
1094
  angle (Number, deg): Value to which the heading should be reset.
962
1095
  """
@@ -985,6 +1118,41 @@ class IMU(Accelerometer):
985
1118
  this returns a vector of accelerations along all axes.
986
1119
  """
987
1120
 
1121
+ def rotation(self, axis: Axis) -> float:
1122
+ """
1123
+ rotation(axis) -> float: deg
1124
+
1125
+ Gets the rotation of the device along a given axis in
1126
+ the :ref:`robot reference frame <robotframe>`.
1127
+
1128
+ This value is useful if your robot *only* rotates along the requested
1129
+ axis. For general three-dimensional motion, use the
1130
+ ``orientation()`` method instead.
1131
+
1132
+ The value starts counting from ``0`` when you initialize this class.
1133
+
1134
+ Arguments:
1135
+ axis (Axis): Axis along which the rotation should be measured.
1136
+ Returns:
1137
+ The rotation angle.
1138
+ """
1139
+
1140
+ def orientation(self) -> Matrix:
1141
+ """
1142
+ orientation() -> Matrix
1143
+
1144
+ Gets the three-dimensional orientation of the robot in
1145
+ the :ref:`robot reference frame <robotframe>`.
1146
+
1147
+ It returns a rotation matrix whose columns represent the ``X``, ``Y``,
1148
+ and ``Z`` axis of the robot.
1149
+
1150
+ .. note:: This method is not yet implemented.
1151
+
1152
+ Returns:
1153
+ The rotation matrix.
1154
+ """
1155
+
988
1156
 
989
1157
  class CommonColorSensor:
990
1158
  """Generic color sensor that supports Pybricks color calibration."""
@@ -1117,3 +1285,79 @@ class AmbientColorSensor(CommonColorSensor):
1117
1285
  Measured color. The color is described by a hue (0--359), a
1118
1286
  saturation (0--100), and a brightness value (0--100).
1119
1287
  """
1288
+
1289
+
1290
+ class BLE:
1291
+ """
1292
+ Bluetooth Low Energy.
1293
+
1294
+ .. versionadded:: 3.3
1295
+ """
1296
+
1297
+ def broadcast(self, *args: Union[None, bool, int, float, str, bytes]) -> None:
1298
+ """broadcast(data0, data1, ...)
1299
+
1300
+ Starts broadcasting the given data values.
1301
+
1302
+ Each value can be any of ``int``, ``float``, ``str`, ``bytes``,
1303
+ ``None``, ``True``, or ``False``. The data is broadcasted on the
1304
+ *broadcast_channel* you selected when initializing the hub.
1305
+
1306
+ The total data size is quite limited (26 bytes). ``None``, ``True`` and
1307
+ ``False`` take 1 byte each. ``float`` takes 5 bytes. ``int`` takes 2 to
1308
+ 5 bytes depending on how big the number is. ``str`` and ``bytes`` take
1309
+ the number of bytes in the object plus one extra byte.
1310
+
1311
+ Params:
1312
+ args: Zero or more values to be broadcast.
1313
+
1314
+
1315
+
1316
+ .. versionadded:: 3.3
1317
+ """
1318
+
1319
+ def observe(
1320
+ self, channel: int
1321
+ ) -> Optional[Tuple[Union[None, bool, int, float, str, bytes], ...]]:
1322
+ """observe(channel) -> tuple | None
1323
+
1324
+ Retrieves the last observed data for a given channel.
1325
+
1326
+ Args:
1327
+ channel (int): The channel to observe (0 to 255).
1328
+
1329
+ Returns:
1330
+ A tuple of the received data or ``None`` if no recent data is
1331
+ available.
1332
+
1333
+ .. tip:: Receiving data is more reliable when the hub is not connected
1334
+ to a computer or other devices at the same time.
1335
+
1336
+ .. versionadded:: 3.3
1337
+ """
1338
+
1339
+ def signal_strength(self, channel: int) -> int:
1340
+ """signal_strength(channel) -> int: dBm
1341
+
1342
+ Gets the average signal strength in dBm for the given channel.
1343
+
1344
+ This is useful for detecting how near the broadcasting device is. A close
1345
+ device may have a signal strength around -40 dBm while a far away device
1346
+ might have a signal strength around -70 dBm.
1347
+
1348
+ Args:
1349
+ channel (int): The channel number (0 to 255).
1350
+
1351
+ Returns:
1352
+ The signal strength or ``-128`` if there is no recent observed data.
1353
+
1354
+ .. versionadded:: 3.3
1355
+ """
1356
+
1357
+ def version(self) -> str:
1358
+ """version() -> str
1359
+
1360
+ Gets the firmware version from the Bluetooth chip.
1361
+
1362
+ .. versionadded:: 3.3
1363
+ """
@@ -168,14 +168,12 @@ class InfraredSensor:
168
168
  class GyroSensor:
169
169
  """LEGO® MINDSTORMS® EV3 Gyro Sensor."""
170
170
 
171
- def __init__(
172
- self, port: _Port, positive_direction: _Direction = _Direction.CLOCKWISE
173
- ):
171
+ def __init__(self, port: _Port, direction: _Direction = _Direction.CLOCKWISE):
174
172
  """GyroSensor(port)
175
173
 
176
174
  Arguments:
177
175
  port (Port): Port to which the sensor is connected.
178
- positive_direction (Direction):
176
+ direction (Direction):
179
177
  Positive rotation direction when looking at the red dot on top
180
178
  of the sensor.
181
179
 
@@ -1,12 +1,14 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2018-2022 The Pybricks Authors
2
+ # Copyright (c) 2018-2023 The Pybricks Authors
3
3
 
4
4
  """LEGO® Programmable Hubs."""
5
+
6
+ from typing import Sequence
7
+
5
8
  from . import _common
6
9
  from .ev3dev import _speaker
7
- from .geometry import Axis
8
10
  from .media.ev3dev import Image as _Image
9
- from .parameters import Button as _Button
11
+ from .parameters import Button as _Button, Axis
10
12
 
11
13
 
12
14
  class EV3Brick:
@@ -39,6 +41,25 @@ class MoveHub:
39
41
  imu = _common.SimpleAccelerometer()
40
42
  system = _common.System()
41
43
  button = _common.Keypad([_Button.CENTER])
44
+ ble = _common.BLE()
45
+
46
+ def __init__(
47
+ self, broadcast_channel: int = 0, observe_channels: Sequence[int] = []
48
+ ):
49
+ """MoveHub(broadcast_channel=0, observe_channels=[])
50
+
51
+ Arguments:
52
+ broadcast_channel:
53
+ A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
54
+ will use. Default is channel 0.
55
+ observe_channels:
56
+ A list of channels to listen to when ``hub.ble.observe()`` is
57
+ called. Listening to more channels requires more memory.
58
+ Default is an empty list (no channels).
59
+
60
+ .. versionchanged:: 3.3
61
+ Added *broadcast_channel* and *observe_channels* arguments.
62
+ """
42
63
 
43
64
 
44
65
  class CityHub:
@@ -50,6 +71,25 @@ class CityHub:
50
71
  light = _common.ColorLight()
51
72
  system = _common.System()
52
73
  button = _common.Keypad([_Button.CENTER])
74
+ ble = _common.BLE()
75
+
76
+ def __init__(
77
+ self, broadcast_channel: int = 0, observe_channels: Sequence[int] = []
78
+ ):
79
+ """CityHub(broadcast_channel=0, observe_channels=[])
80
+
81
+ Arguments:
82
+ broadcast_channel:
83
+ A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
84
+ will use. Default is channel 0.
85
+ observe_channels:
86
+ A list of channels to listen to when ``hub.ble.observe()`` is
87
+ called. Listening to more channels requires more memory.
88
+ Default is an empty list (no channels).
89
+
90
+ .. versionchanged:: 3.3
91
+ Added *broadcast_channel* and *observe_channels* arguments.
92
+ """
53
93
 
54
94
 
55
95
  class TechnicHub:
@@ -62,9 +102,16 @@ class TechnicHub:
62
102
  imu = _common.IMU()
63
103
  system = _common.System()
64
104
  button = _common.Keypad([_Button.CENTER])
105
+ ble = _common.BLE()
65
106
 
66
- def __init__(self, top_side: Axis = Axis.Z, front_side: Axis = Axis.X):
67
- """TechnicHub(top_side=Axis.Z, front_side=Axis.X)
107
+ def __init__(
108
+ self,
109
+ top_side: Axis = Axis.Z,
110
+ front_side: Axis = Axis.X,
111
+ broadcast_channel: int = 0,
112
+ observe_channels: Sequence[int] = [],
113
+ ):
114
+ """TechnicHub(top_side=Axis.Z, front_side=Axis.X, broadcast_channel=0, observe_channels=[])
68
115
 
69
116
  Initializes the hub. Optionally, specify how the hub is
70
117
  :ref:`placed in your design <robotframe>` by saying in which
@@ -76,6 +123,16 @@ class TechnicHub:
76
123
  the hub.
77
124
  front_side (Axis): The axis that passes through the *front side* of
78
125
  the hub.
126
+ broadcast_channel:
127
+ A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
128
+ will use. Default is channel 0.
129
+ observe_channels:
130
+ A list of channels to listen to when ``hub.ble.observe()`` is
131
+ called. Listening to more channels requires more memory.
132
+ Default is an empty list (no channels).
133
+
134
+ .. versionchanged:: 3.3
135
+ Added *broadcast_channel* and *observe_channels* arguments.
79
136
  """
80
137
 
81
138
 
@@ -90,9 +147,16 @@ class EssentialHub:
90
147
  light = _common.ColorLight()
91
148
  imu = _common.IMU()
92
149
  system = _common.System()
150
+ ble = _common.BLE()
93
151
 
94
- def __init__(self, top_side=Axis.Z, front_side=Axis.X):
95
- """__init__(top_side=Axis.Z, front_side=Axis.X)
152
+ def __init__(
153
+ self,
154
+ top_side: Axis = Axis.Z,
155
+ front_side: Axis = Axis.X,
156
+ broadcast_channel: int = 0,
157
+ observe_channels: Sequence[int] = [],
158
+ ):
159
+ """EssentialHub(top_side=Axis.Z, front_side=Axis.X, broadcast_channel=0, observe_channels=[])
96
160
 
97
161
  Initializes the hub. Optionally, specify how the hub is
98
162
  :ref:`placed in your design <robotframe>` by saying in which
@@ -104,6 +168,16 @@ class EssentialHub:
104
168
  the hub.
105
169
  front_side (Axis): The axis that passes through the *front side* of
106
170
  the hub.
171
+ broadcast_channel:
172
+ A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
173
+ will use. Default is channel 0.
174
+ observe_channels:
175
+ A list of channels to listen to when ``hub.ble.observe()`` is
176
+ called. Listening to more channels requires more memory.
177
+ Default is an empty list (no channels).
178
+
179
+ .. versionchanged:: 3.3
180
+ Added *broadcast_channel* and *observe_channels* arguments.
107
181
  """
108
182
  pass
109
183
 
@@ -128,9 +202,16 @@ class PrimeHub:
128
202
  speaker = _common.Speaker()
129
203
  imu = _common.IMU()
130
204
  system = _common.System()
205
+ ble = _common.BLE()
131
206
 
132
- def __init__(self, top_side: Axis = Axis.Z, front_side: Axis = Axis.X):
133
- """PrimeHub(top_side=Axis.Z, front_side=Axis.X)
207
+ def __init__(
208
+ self,
209
+ top_side: Axis = Axis.Z,
210
+ front_side: Axis = Axis.X,
211
+ broadcast_channel: int = 0,
212
+ observe_channels: Sequence[int] = [],
213
+ ):
214
+ """PrimeHub(top_side=Axis.Z, front_side=Axis.X, broadcast_channel=0, observe_channels=[])
134
215
 
135
216
  Initializes the hub. Optionally, specify how the hub is
136
217
  :ref:`placed in your design <robotframe>` by saying in which
@@ -142,6 +223,16 @@ class PrimeHub:
142
223
  the hub.
143
224
  front_side (Axis): The axis that passes through the *front side* of
144
225
  the hub.
226
+ broadcast_channel:
227
+ A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
228
+ will use. Default is channel 0.
229
+ observe_channels:
230
+ A list of channels to listen to when ``hub.ble.observe()`` is
231
+ called. Listening to more channels requires more memory.
232
+ Default is an empty list (no channels).
233
+
234
+ .. versionchanged:: 3.3
235
+ Added *broadcast_channel* and *observe_channels* arguments.
145
236
  """
146
237
 
147
238
 
@@ -9,7 +9,7 @@ from enum import Enum
9
9
  from typing import Union, TYPE_CHECKING
10
10
  import os
11
11
 
12
- from .geometry import Matrix as _Matrix
12
+ from .tools import Matrix as _Matrix, vector as _vector
13
13
 
14
14
  if TYPE_CHECKING or os.environ.get("SPHINX_BUILD") == "True":
15
15
  Number = Union[int, float]
@@ -57,6 +57,20 @@ class _PybricksEnum(Enum, metaclass=_PybricksEnumMeta):
57
57
  return str(self)
58
58
 
59
59
 
60
+ class Axis:
61
+ """Unit axes of a coordinate system.
62
+
63
+ .. data:: X = vector(1, 0, 0)
64
+ .. data:: Y = vector(0, 1, 0)
65
+ .. data:: Z = vector(0, 0, 1)
66
+
67
+ """
68
+
69
+ X: _Matrix = _vector(1, 0, 0)
70
+ Y: _Matrix = _vector(0, 1, 0)
71
+ Z: _Matrix = _vector(0, 0, 1)
72
+
73
+
60
74
  class Color:
61
75
  """Light or surface color."""
62
76