From b0ffb24a2e3615d8276167a9b8223be36039f47b Mon Sep 17 00:00:00 2001 From: Laurens Valk Date: Wed, 4 Nov 2020 10:04:11 +0100 Subject: [PATCH] examples: import snippets from pybricks-projects These code samples are rendered in the docs, so we include them here. For the git history of these snippets, see: https://github.com/pybricks/pybricks-projects/commits/f4914069aaacfd9ab1e0dd6f05524f62cfc56b29/snippets --- examples/ev3/bluetooth_client/.gitignore | 3 + .../bluetooth_client/.vscode/extensions.json | 13 + .../ev3/bluetooth_client/.vscode/launch.json | 14 + .../bluetooth_client/.vscode/settings.json | 6 + examples/ev3/bluetooth_client/client.py | 25 ++ examples/ev3/bluetooth_pc/.vscode/launch.json | 15 + examples/ev3/bluetooth_pc/pcclient.py | 33 ++ examples/ev3/bluetooth_pc/pybricks/README.md | 9 + .../ev3/bluetooth_pc/pybricks/bluetooth.py | 145 ++++++++ .../ev3/bluetooth_pc/pybricks/messaging.py | 340 ++++++++++++++++++ examples/ev3/bluetooth_read_spike/.gitignore | 3 + .../.vscode/extensions.json | 13 + .../bluetooth_read_spike/.vscode/launch.json | 15 + .../.vscode/settings.json | 8 + examples/ev3/bluetooth_read_spike/README.md | 6 + .../ev3/bluetooth_read_spike/connection.py | 80 +++++ examples/ev3/bluetooth_read_spike/main.py | 17 + examples/ev3/bluetooth_read_spike/rover.py | 28 ++ examples/ev3/bluetooth_server/.gitignore | 3 + .../bluetooth_server/.vscode/extensions.json | 13 + .../ev3/bluetooth_server/.vscode/launch.json | 14 + .../bluetooth_server/.vscode/settings.json | 6 + examples/ev3/bluetooth_server/server.py | 23 ++ examples/ev3/buttons/.gitignore | 3 + examples/ev3/buttons/.vscode/extensions.json | 13 + examples/ev3/buttons/.vscode/launch.json | 14 + examples/ev3/buttons/.vscode/settings.json | 6 + examples/ev3/buttons/main.py | 20 ++ examples/ev3/buttons_quickstart/.gitignore | 3 + .../.vscode/extensions.json | 13 + .../buttons_quickstart/.vscode/launch.json | 14 + .../buttons_quickstart/.vscode/settings.json | 7 + examples/ev3/buttons_quickstart/buttons.png | Bin 0 -> 2651 bytes examples/ev3/buttons_quickstart/buttons.svg | 101 ++++++ examples/ev3/buttons_quickstart/main.py | 27 ++ examples/ev3/buttons_quickstart/menu.py | 30 ++ examples/ev3/datalog/.gitignore | 3 + examples/ev3/datalog/.vscode/extensions.json | 13 + examples/ev3/datalog/.vscode/launch.json | 15 + examples/ev3/datalog/.vscode/settings.json | 7 + examples/ev3/datalog/main.py | 34 ++ examples/ev3/datalog_extra/.gitignore | 3 + .../ev3/datalog_extra/.vscode/extensions.json | 13 + .../ev3/datalog_extra/.vscode/launch.json | 15 + .../ev3/datalog_extra/.vscode/settings.json | 7 + examples/ev3/datalog_extra/main.py | 15 + examples/ev3/ev3devsensor/.gitignore | 3 + .../ev3/ev3devsensor/.vscode/extensions.json | 13 + examples/ev3/ev3devsensor/.vscode/launch.json | 20 ++ .../ev3/ev3devsensor/.vscode/settings.json | 6 + examples/ev3/ev3devsensor/class_example.py | 46 +++ examples/ev3/ev3devsensor/main.py | 19 + examples/ev3/getting_started/.gitignore | 3 + .../getting_started/.vscode/extensions.json | 13 + .../ev3/getting_started/.vscode/launch.json | 15 + .../ev3/getting_started/.vscode/settings.json | 6 + examples/ev3/getting_started/main.py | 23 ++ examples/ev3/i2c_basics/.gitignore | 3 + .../ev3/i2c_basics/.vscode/extensions.json | 13 + examples/ev3/i2c_basics/.vscode/launch.json | 14 + examples/ev3/i2c_basics/.vscode/settings.json | 6 + examples/ev3/i2c_basics/main.py | 23 ++ examples/ev3/i2c_extra/.gitignore | 3 + .../ev3/i2c_extra/.vscode/extensions.json | 13 + examples/ev3/i2c_extra/.vscode/launch.json | 14 + examples/ev3/i2c_extra/.vscode/settings.json | 6 + examples/ev3/i2c_extra/main.py | 35 ++ examples/ev3/light_color/.gitignore | 3 + .../ev3/light_color/.vscode/extensions.json | 13 + examples/ev3/light_color/.vscode/launch.json | 14 + .../ev3/light_color/.vscode/settings.json | 6 + examples/ev3/light_color/main.py | 17 + examples/ev3/ps4/.gitignore | 3 + examples/ev3/ps4/.vscode/extensions.json | 13 + examples/ev3/ps4/.vscode/launch.json | 15 + examples/ev3/ps4/.vscode/settings.json | 7 + examples/ev3/ps4/main.py | 145 ++++++++ examples/ev3/rcx_touch/.gitignore | 3 + .../ev3/rcx_touch/.vscode/extensions.json | 13 + examples/ev3/rcx_touch/.vscode/launch.json | 15 + examples/ev3/rcx_touch/.vscode/settings.json | 7 + examples/ev3/rcx_touch/main.py | 21 ++ examples/ev3/screen_draw/.gitignore | 3 + .../ev3/screen_draw/.vscode/extensions.json | 13 + examples/ev3/screen_draw/.vscode/launch.json | 14 + .../ev3/screen_draw/.vscode/settings.json | 6 + examples/ev3/screen_draw/main.py | 32 ++ examples/ev3/screen_extra/.gitignore | 3 + .../ev3/screen_extra/.vscode/extensions.json | 13 + examples/ev3/screen_extra/.vscode/launch.json | 14 + .../ev3/screen_extra/.vscode/settings.json | 6 + examples/ev3/screen_extra/background.png | Bin 0 -> 3664 bytes examples/ev3/screen_extra/main.py | 104 ++++++ examples/ev3/screen_extra/sprite.png | Bin 0 -> 40847 bytes examples/ev3/screen_image/.gitignore | 3 + .../ev3/screen_image/.vscode/extensions.json | 13 + examples/ev3/screen_image/.vscode/launch.json | 14 + .../ev3/screen_image/.vscode/settings.json | 6 + examples/ev3/screen_image/main.py | 20 ++ examples/ev3/screen_print/.gitignore | 3 + .../ev3/screen_print/.vscode/extensions.json | 13 + examples/ev3/screen_print/.vscode/launch.json | 14 + .../ev3/screen_print/.vscode/settings.json | 6 + examples/ev3/screen_print/main.py | 34 ++ examples/ev3/speaker_basics/.gitignore | 3 + .../speaker_basics/.vscode/extensions.json | 13 + .../ev3/speaker_basics/.vscode/launch.json | 14 + .../ev3/speaker_basics/.vscode/settings.json | 6 + examples/ev3/speaker_basics/main.py | 55 +++ examples/ev3/uart_basics/.gitignore | 3 + .../ev3/uart_basics/.vscode/extensions.json | 13 + examples/ev3/uart_basics/.vscode/launch.json | 14 + .../ev3/uart_basics/.vscode/settings.json | 6 + examples/ev3/uart_basics/main.py | 25 ++ .../vernier_surface_temperature/.gitignore | 3 + .../.vscode/extensions.json | 13 + .../.vscode/launch.json | 14 + .../.vscode/settings.json | 6 + .../ev3/vernier_surface_temperature/main.py | 32 ++ examples/pup/hub_cityhub/light_animate.py | 23 ++ examples/pup/hub_cityhub/light_blink.py | 16 + examples/pup/hub_cityhub/light_hsv.py | 21 ++ examples/pup/hub_cityhub/light_off.py | 15 + examples/pup/hub_inventorhub/light_animate.py | 23 ++ examples/pup/hub_inventorhub/light_blink.py | 16 + examples/pup/hub_inventorhub/light_hsv.py | 21 ++ examples/pup/hub_inventorhub/light_off.py | 15 + examples/pup/hub_movehub/light_animate.py | 16 + examples/pup/hub_movehub/light_blink.py | 16 + examples/pup/hub_movehub/light_hsv.py | 16 + examples/pup/hub_movehub/light_off.py | 15 + examples/pup/hub_primehub/light_animate.py | 23 ++ examples/pup/hub_primehub/light_blink.py | 16 + examples/pup/hub_primehub/light_hsv.py | 21 ++ examples/pup/hub_primehub/light_off.py | 15 + examples/pup/hub_shared/light_animate.py | 25 ++ examples/pup/hub_shared/light_blink.py | 16 + examples/pup/hub_shared/light_hsv.py | 22 ++ examples/pup/hub_shared/light_off.py | 15 + .../pup/hub_shared/make_shared_examples.py | 56 +++ examples/pup/hub_technichub/light_animate.py | 23 ++ examples/pup/hub_technichub/light_blink.py | 16 + examples/pup/hub_technichub/light_hsv.py | 21 ++ examples/pup/hub_technichub/light_off.py | 15 + examples/pup/light/basics.py | 16 + examples/pup/light/math.py | 27 ++ examples/pup/motor/motor_action_basic.py | 46 +++ examples/pup/motor/motor_action_then.py | 24 ++ examples/pup/motor/motor_action_wait.py | 14 + .../pup/motor/motor_action_wait_advanced.py | 18 + examples/pup/motor/motor_init_basic.py | 18 + examples/pup/motor/motor_init_direction.py | 16 + examples/pup/motor/motor_init_gears.py | 15 + examples/pup/motor/motor_init_multiple.py | 14 + examples/pup/motor/motor_measure.py | 22 ++ examples/pup/motor/motor_reset_angle.py | 17 + examples/pup/motor/motor_stop.py | 30 ++ examples/pup/motor/motor_until_stalled.py | 26 ++ .../pup/motor/motor_until_stalled_center.py | 24 ++ examples/pup/motor_dc/motor_dc_init_basic.py | 18 + .../pup/motor_dc/motor_dc_init_direction.py | 17 + examples/pup/motor_dc/motor_dc_stop.py | 16 + examples/pup/motor_pf/motor_pf_basics.py | 20 ++ examples/pup/motor_pf/motor_pf_pwm.py | 25 ++ examples/pup/sensor_color/color_ambient.py | 26 ++ examples/pup/sensor_color/color_print.py | 20 ++ .../pup/sensor_color/detectable_colors.py | 39 ++ examples/pup/sensor_color/hsv.py | 21 ++ examples/pup/sensor_color/lights_blink.py | 27 ++ examples/pup/sensor_color/wait_for_color.py | 27 ++ .../pup/sensor_color_distance/color_print.py | 19 + .../detectable_colors.py | 39 ++ .../sensor_color_distance/distance_blink.py | 23 ++ examples/pup/sensor_color_distance/hsv.py | 21 ++ .../sensor_color_distance/wait_for_color.py | 27 ++ examples/pup/sensor_force/basics.py | 21 ++ examples/pup/sensor_force/peak.py | 45 +++ examples/pup/sensor_infrared/basics.py | 21 ++ examples/pup/sensor_tilt/basics.py | 16 + examples/pup/sensor_ultrasonic/basics.py | 21 ++ examples/pup/sensor_ultrasonic/math.py | 32 ++ 181 files changed, 3719 insertions(+) create mode 100644 examples/ev3/bluetooth_client/.gitignore create mode 100644 examples/ev3/bluetooth_client/.vscode/extensions.json create mode 100644 examples/ev3/bluetooth_client/.vscode/launch.json create mode 100644 examples/ev3/bluetooth_client/.vscode/settings.json create mode 100644 examples/ev3/bluetooth_client/client.py create mode 100644 examples/ev3/bluetooth_pc/.vscode/launch.json create mode 100644 examples/ev3/bluetooth_pc/pcclient.py create mode 100644 examples/ev3/bluetooth_pc/pybricks/README.md create mode 100644 examples/ev3/bluetooth_pc/pybricks/bluetooth.py create mode 100644 examples/ev3/bluetooth_pc/pybricks/messaging.py create mode 100644 examples/ev3/bluetooth_read_spike/.gitignore create mode 100644 examples/ev3/bluetooth_read_spike/.vscode/extensions.json create mode 100644 examples/ev3/bluetooth_read_spike/.vscode/launch.json create mode 100644 examples/ev3/bluetooth_read_spike/.vscode/settings.json create mode 100644 examples/ev3/bluetooth_read_spike/README.md create mode 100644 examples/ev3/bluetooth_read_spike/connection.py create mode 100644 examples/ev3/bluetooth_read_spike/main.py create mode 100644 examples/ev3/bluetooth_read_spike/rover.py create mode 100644 examples/ev3/bluetooth_server/.gitignore create mode 100644 examples/ev3/bluetooth_server/.vscode/extensions.json create mode 100644 examples/ev3/bluetooth_server/.vscode/launch.json create mode 100644 examples/ev3/bluetooth_server/.vscode/settings.json create mode 100644 examples/ev3/bluetooth_server/server.py create mode 100644 examples/ev3/buttons/.gitignore create mode 100644 examples/ev3/buttons/.vscode/extensions.json create mode 100644 examples/ev3/buttons/.vscode/launch.json create mode 100644 examples/ev3/buttons/.vscode/settings.json create mode 100644 examples/ev3/buttons/main.py create mode 100644 examples/ev3/buttons_quickstart/.gitignore create mode 100644 examples/ev3/buttons_quickstart/.vscode/extensions.json create mode 100644 examples/ev3/buttons_quickstart/.vscode/launch.json create mode 100644 examples/ev3/buttons_quickstart/.vscode/settings.json create mode 100644 examples/ev3/buttons_quickstart/buttons.png create mode 100644 examples/ev3/buttons_quickstart/buttons.svg create mode 100644 examples/ev3/buttons_quickstart/main.py create mode 100644 examples/ev3/buttons_quickstart/menu.py create mode 100644 examples/ev3/datalog/.gitignore create mode 100644 examples/ev3/datalog/.vscode/extensions.json create mode 100644 examples/ev3/datalog/.vscode/launch.json create mode 100644 examples/ev3/datalog/.vscode/settings.json create mode 100644 examples/ev3/datalog/main.py create mode 100644 examples/ev3/datalog_extra/.gitignore create mode 100644 examples/ev3/datalog_extra/.vscode/extensions.json create mode 100644 examples/ev3/datalog_extra/.vscode/launch.json create mode 100644 examples/ev3/datalog_extra/.vscode/settings.json create mode 100644 examples/ev3/datalog_extra/main.py create mode 100644 examples/ev3/ev3devsensor/.gitignore create mode 100644 examples/ev3/ev3devsensor/.vscode/extensions.json create mode 100644 examples/ev3/ev3devsensor/.vscode/launch.json create mode 100644 examples/ev3/ev3devsensor/.vscode/settings.json create mode 100644 examples/ev3/ev3devsensor/class_example.py create mode 100644 examples/ev3/ev3devsensor/main.py create mode 100644 examples/ev3/getting_started/.gitignore create mode 100644 examples/ev3/getting_started/.vscode/extensions.json create mode 100644 examples/ev3/getting_started/.vscode/launch.json create mode 100644 examples/ev3/getting_started/.vscode/settings.json create mode 100644 examples/ev3/getting_started/main.py create mode 100644 examples/ev3/i2c_basics/.gitignore create mode 100644 examples/ev3/i2c_basics/.vscode/extensions.json create mode 100644 examples/ev3/i2c_basics/.vscode/launch.json create mode 100644 examples/ev3/i2c_basics/.vscode/settings.json create mode 100644 examples/ev3/i2c_basics/main.py create mode 100644 examples/ev3/i2c_extra/.gitignore create mode 100644 examples/ev3/i2c_extra/.vscode/extensions.json create mode 100644 examples/ev3/i2c_extra/.vscode/launch.json create mode 100644 examples/ev3/i2c_extra/.vscode/settings.json create mode 100644 examples/ev3/i2c_extra/main.py create mode 100644 examples/ev3/light_color/.gitignore create mode 100644 examples/ev3/light_color/.vscode/extensions.json create mode 100644 examples/ev3/light_color/.vscode/launch.json create mode 100644 examples/ev3/light_color/.vscode/settings.json create mode 100644 examples/ev3/light_color/main.py create mode 100644 examples/ev3/ps4/.gitignore create mode 100644 examples/ev3/ps4/.vscode/extensions.json create mode 100644 examples/ev3/ps4/.vscode/launch.json create mode 100644 examples/ev3/ps4/.vscode/settings.json create mode 100644 examples/ev3/ps4/main.py create mode 100644 examples/ev3/rcx_touch/.gitignore create mode 100644 examples/ev3/rcx_touch/.vscode/extensions.json create mode 100644 examples/ev3/rcx_touch/.vscode/launch.json create mode 100644 examples/ev3/rcx_touch/.vscode/settings.json create mode 100644 examples/ev3/rcx_touch/main.py create mode 100644 examples/ev3/screen_draw/.gitignore create mode 100644 examples/ev3/screen_draw/.vscode/extensions.json create mode 100644 examples/ev3/screen_draw/.vscode/launch.json create mode 100644 examples/ev3/screen_draw/.vscode/settings.json create mode 100644 examples/ev3/screen_draw/main.py create mode 100644 examples/ev3/screen_extra/.gitignore create mode 100644 examples/ev3/screen_extra/.vscode/extensions.json create mode 100644 examples/ev3/screen_extra/.vscode/launch.json create mode 100644 examples/ev3/screen_extra/.vscode/settings.json create mode 100644 examples/ev3/screen_extra/background.png create mode 100644 examples/ev3/screen_extra/main.py create mode 100644 examples/ev3/screen_extra/sprite.png create mode 100644 examples/ev3/screen_image/.gitignore create mode 100644 examples/ev3/screen_image/.vscode/extensions.json create mode 100644 examples/ev3/screen_image/.vscode/launch.json create mode 100644 examples/ev3/screen_image/.vscode/settings.json create mode 100644 examples/ev3/screen_image/main.py create mode 100644 examples/ev3/screen_print/.gitignore create mode 100644 examples/ev3/screen_print/.vscode/extensions.json create mode 100644 examples/ev3/screen_print/.vscode/launch.json create mode 100644 examples/ev3/screen_print/.vscode/settings.json create mode 100644 examples/ev3/screen_print/main.py create mode 100644 examples/ev3/speaker_basics/.gitignore create mode 100644 examples/ev3/speaker_basics/.vscode/extensions.json create mode 100644 examples/ev3/speaker_basics/.vscode/launch.json create mode 100644 examples/ev3/speaker_basics/.vscode/settings.json create mode 100644 examples/ev3/speaker_basics/main.py create mode 100644 examples/ev3/uart_basics/.gitignore create mode 100644 examples/ev3/uart_basics/.vscode/extensions.json create mode 100644 examples/ev3/uart_basics/.vscode/launch.json create mode 100644 examples/ev3/uart_basics/.vscode/settings.json create mode 100644 examples/ev3/uart_basics/main.py create mode 100644 examples/ev3/vernier_surface_temperature/.gitignore create mode 100644 examples/ev3/vernier_surface_temperature/.vscode/extensions.json create mode 100644 examples/ev3/vernier_surface_temperature/.vscode/launch.json create mode 100644 examples/ev3/vernier_surface_temperature/.vscode/settings.json create mode 100644 examples/ev3/vernier_surface_temperature/main.py create mode 100644 examples/pup/hub_cityhub/light_animate.py create mode 100644 examples/pup/hub_cityhub/light_blink.py create mode 100644 examples/pup/hub_cityhub/light_hsv.py create mode 100644 examples/pup/hub_cityhub/light_off.py create mode 100644 examples/pup/hub_inventorhub/light_animate.py create mode 100644 examples/pup/hub_inventorhub/light_blink.py create mode 100644 examples/pup/hub_inventorhub/light_hsv.py create mode 100644 examples/pup/hub_inventorhub/light_off.py create mode 100644 examples/pup/hub_movehub/light_animate.py create mode 100644 examples/pup/hub_movehub/light_blink.py create mode 100644 examples/pup/hub_movehub/light_hsv.py create mode 100644 examples/pup/hub_movehub/light_off.py create mode 100644 examples/pup/hub_primehub/light_animate.py create mode 100644 examples/pup/hub_primehub/light_blink.py create mode 100644 examples/pup/hub_primehub/light_hsv.py create mode 100644 examples/pup/hub_primehub/light_off.py create mode 100644 examples/pup/hub_shared/light_animate.py create mode 100644 examples/pup/hub_shared/light_blink.py create mode 100644 examples/pup/hub_shared/light_hsv.py create mode 100644 examples/pup/hub_shared/light_off.py create mode 100644 examples/pup/hub_shared/make_shared_examples.py create mode 100644 examples/pup/hub_technichub/light_animate.py create mode 100644 examples/pup/hub_technichub/light_blink.py create mode 100644 examples/pup/hub_technichub/light_hsv.py create mode 100644 examples/pup/hub_technichub/light_off.py create mode 100644 examples/pup/light/basics.py create mode 100644 examples/pup/light/math.py create mode 100644 examples/pup/motor/motor_action_basic.py create mode 100644 examples/pup/motor/motor_action_then.py create mode 100644 examples/pup/motor/motor_action_wait.py create mode 100644 examples/pup/motor/motor_action_wait_advanced.py create mode 100644 examples/pup/motor/motor_init_basic.py create mode 100644 examples/pup/motor/motor_init_direction.py create mode 100644 examples/pup/motor/motor_init_gears.py create mode 100644 examples/pup/motor/motor_init_multiple.py create mode 100644 examples/pup/motor/motor_measure.py create mode 100644 examples/pup/motor/motor_reset_angle.py create mode 100644 examples/pup/motor/motor_stop.py create mode 100644 examples/pup/motor/motor_until_stalled.py create mode 100644 examples/pup/motor/motor_until_stalled_center.py create mode 100644 examples/pup/motor_dc/motor_dc_init_basic.py create mode 100644 examples/pup/motor_dc/motor_dc_init_direction.py create mode 100644 examples/pup/motor_dc/motor_dc_stop.py create mode 100644 examples/pup/motor_pf/motor_pf_basics.py create mode 100644 examples/pup/motor_pf/motor_pf_pwm.py create mode 100644 examples/pup/sensor_color/color_ambient.py create mode 100644 examples/pup/sensor_color/color_print.py create mode 100644 examples/pup/sensor_color/detectable_colors.py create mode 100644 examples/pup/sensor_color/hsv.py create mode 100644 examples/pup/sensor_color/lights_blink.py create mode 100644 examples/pup/sensor_color/wait_for_color.py create mode 100644 examples/pup/sensor_color_distance/color_print.py create mode 100644 examples/pup/sensor_color_distance/detectable_colors.py create mode 100644 examples/pup/sensor_color_distance/distance_blink.py create mode 100644 examples/pup/sensor_color_distance/hsv.py create mode 100644 examples/pup/sensor_color_distance/wait_for_color.py create mode 100644 examples/pup/sensor_force/basics.py create mode 100644 examples/pup/sensor_force/peak.py create mode 100644 examples/pup/sensor_infrared/basics.py create mode 100644 examples/pup/sensor_tilt/basics.py create mode 100644 examples/pup/sensor_ultrasonic/basics.py create mode 100644 examples/pup/sensor_ultrasonic/math.py diff --git a/examples/ev3/bluetooth_client/.gitignore b/examples/ev3/bluetooth_client/.gitignore new file mode 100644 index 0000000..9b5f630 --- /dev/null +++ b/examples/ev3/bluetooth_client/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +venv/ diff --git a/examples/ev3/bluetooth_client/.vscode/extensions.json b/examples/ev3/bluetooth_client/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/bluetooth_client/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/bluetooth_client/.vscode/launch.json b/examples/ev3/bluetooth_client/.vscode/launch.json new file mode 100644 index 0000000..4b8308d --- /dev/null +++ b/examples/ev3/bluetooth_client/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/client.py" + } + ] +} diff --git a/examples/ev3/bluetooth_client/.vscode/settings.json b/examples/ev3/bluetooth_client/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/bluetooth_client/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/bluetooth_client/client.py b/examples/ev3/bluetooth_client/client.py new file mode 100644 index 0000000..f90ab06 --- /dev/null +++ b/examples/ev3/bluetooth_client/client.py @@ -0,0 +1,25 @@ +#!/usr/bin/env pybricks-micropython + +# Before running this program, make sure the client and server EV3 bricks are +# paired using Bluetooth, but do NOT connect them. The program will take care +# of establishing the connection. + +# The server must be started before the client! + +from pybricks.messaging import BluetoothMailboxClient, TextMailbox + +# This is the name of the remote EV3 or PC we are connecting to. +SERVER = 'ev3dev' + +client = BluetoothMailboxClient() +mbox = TextMailbox('greeting', client) + +print('establishing connection...') +client.connect(SERVER) +print('connected!') + +# In this program, the client sends the first message and then waits for the +# server to reply. +mbox.send('hello!') +mbox.wait() +print(mbox.read()) diff --git a/examples/ev3/bluetooth_pc/.vscode/launch.json b/examples/ev3/bluetooth_pc/.vscode/launch.json new file mode 100644 index 0000000..2c05c3c --- /dev/null +++ b/examples/ev3/bluetooth_pc/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "PC Bluetooth Example", + "type": "python", + "request": "launch", + "program": "pcclient.py", + "console": "integratedTerminal" + } + ] +} diff --git a/examples/ev3/bluetooth_pc/pcclient.py b/examples/ev3/bluetooth_pc/pcclient.py new file mode 100644 index 0000000..ffc1ee2 --- /dev/null +++ b/examples/ev3/bluetooth_pc/pcclient.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +from pybricks.messaging import BluetoothMailboxClient, TextMailbox + +# This demo makes your PC talk to an EV3 over Bluetooth. +# +# This is identical to the EV3 client example in ../bluetooth_client +# +# The only difference is that it runs in Python3 on your computer, thanks to +# the Python3 implementation of the messaging module that is included here. +# As far as the EV3 is concerned, it thinks it just talks to an EV3 client. +# +# So, the EV3 server example needs no further modifications. The connection +# procedure is also the same as documented in the messaging module docs: +# https://docs.pybricks.com/en/latest/messaging.html +# +# So, turn Bluetooth on on your PC and the EV3. You may need to make Bluetooth +# visible on the EV3. You can skip pairing if you already know the EV3 address. + +# This is the address of the server EV3 we are connecting to. +SERVER = 'CC:78:AB:D8:4E:F6' + +client = BluetoothMailboxClient() +mbox = TextMailbox('greeting', client) + +print('establishing connection...') +client.connect(SERVER) +print('connected!') + +# In this program, the client sends the first message and then waits for the +# server to reply. +mbox.send('hello!') +mbox.wait() +print(mbox.read()) diff --git a/examples/ev3/bluetooth_pc/pybricks/README.md b/examples/ev3/bluetooth_pc/pybricks/README.md new file mode 100644 index 0000000..0d854b1 --- /dev/null +++ b/examples/ev3/bluetooth_pc/pybricks/README.md @@ -0,0 +1,9 @@ +This is a partial implementation of the pybricks package that is normally +included in Pybricks MicroPython for EV3. It makes the PC look like an EV3 so +other EV3 bricks can connect to it and vice versa. + +It has the same end user API, so the same documentation applies: +https://docs.pybricks.com/en/latest/messaging.html + +This is a Python3 modification of the original Pybricks MicroPython version: +https://github.com/pybricks/pybricks-micropython/tree/master/bricks/ev3dev diff --git a/examples/ev3/bluetooth_pc/pybricks/bluetooth.py b/examples/ev3/bluetooth_pc/pybricks/bluetooth.py new file mode 100644 index 0000000..f7904bd --- /dev/null +++ b/examples/ev3/bluetooth_pc/pybricks/bluetooth.py @@ -0,0 +1,145 @@ +# SPDX-License-Identifier: MIT +# Copyright (C) 2020 The Pybricks Authors + +""" +:class:`RFCOMMServer` can be used to communicate with other Bluetooth RFCOMM +devices that don't support the EV3 mailbox protocol. + +It is based on the standard library ``socketserver`` module and attempts to +remain a strict subset of that implementation when it comes to low-level +implementation details. +""" + +from bluetooth import BluetoothSocket, RFCOMM +from socketserver import ThreadingMixIn + +BDADDR_ANY = "" + + +def str2ba(string, ba): + """Convert string to Bluetooth address""" + for i, v in enumerate(string.split(':')): + ba.b[5-i] = int(v, 16) + + +def ba2str(ba): + """Convert Bluetooth address to string""" + string = [] + for b in ba.b: + string.append('{:02X}'.format(b)) + string.reverse() + return ':'.join(string).upper() + + +class RFCOMMServer: + """Object that simplifies setting up an RFCOMM socket server. + + This is based on the ``socketserver.SocketServer`` class in the Python + standard library. + """ + request_queue_size = 1 + + def __init__(self, server_address, RequestHandlerClass): + self.server_address = server_address + self.RequestHandlerClass = RequestHandlerClass + + self.socket = BluetoothSocket(RFCOMM) + + try: + self.socket.bind((server_address[0], server_address[1])) + # self.server_address = self.socket.getsockname() + self.socket.listen(self.request_queue_size) + except Exception: + self.server_close() + raise + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.server_close() + + def handle_request(self): + try: + request, addr_data = self.socket.accept() + except OSError: + return + + try: + self.process_request(request, addr_data) + except Exception: + request.close() + raise + + def process_request(self, request, client_address): + self.finish_request(request, client_address) + request.close() + + def finish_request(self, request, client_address): + self.RequestHandlerClass(request, client_address, self) + + def server_close(self): + self.socket.close() + + +class StreamRequestHandler: + """Class that handles incoming requests. + + This is based on ``socketserver.StreamRequestHandler`` from the Python + standard library. + """ + def __init__(self, request, client_address, server): + self.request = request + self.client_address = client_address + self.server = server + self.setup() + try: + self.handle() + finally: + self.finish() + + def setup(self): + self.wfile = self.request + self.rfile = self.request + + def handle(self): + pass + + def finish(self): + pass + + +class ThreadingRFCOMMServer(ThreadingMixIn, RFCOMMServer): + """Version of :class:`RFCOMMServer` that handles connections in a new + thread. + """ + pass + + +class RFCOMMClient: + def __init__(self, client_address, RequestHandlerClass): + self.client_address = client_address + self.RequestHandlerClass = RequestHandlerClass + self.socket = BluetoothSocket(RFCOMM) + + def handle_request(self): + self.socket.connect((self.client_address[0], self.client_address[1])) + try: + self.process_request(self.socket, self.client_address) + except Exception: + self.socket.close() + raise + + def process_request(self, request, client_address): + self.finish_request(request, client_address) + request.close() + + def finish_request(self, request, client_address): + self.RequestHandlerClass(request, client_address, self) + + def client_close(self): + self.socket.close() + + +class ThreadingRFCOMMClient(ThreadingMixIn, RFCOMMClient): + pass diff --git a/examples/ev3/bluetooth_pc/pybricks/messaging.py b/examples/ev3/bluetooth_pc/pybricks/messaging.py new file mode 100644 index 0000000..0595f81 --- /dev/null +++ b/examples/ev3/bluetooth_pc/pybricks/messaging.py @@ -0,0 +1,340 @@ +# SPDX-License-Identifier: MIT +# Copyright (C) 2020 The Pybricks Authors + +from _thread import allocate_lock +from errno import ECONNRESET +from struct import pack, unpack + +from .bluetooth import (BDADDR_ANY, ThreadingRFCOMMServer, + ThreadingRFCOMMClient, StreamRequestHandler) + + +def resolve(brick): + """Fake resolver to get address from Bluetooth name. + + To connect to an EV3 server, you must specify its full address. + """ + return brick + + +class Mailbox: + def __init__(self, name, connection, encode=None, decode=None): + """Object that represents a mailbox for sending an receiving messages + from other connected devices. + + Arguments: + name (str): + The name of this mailbox. + connection: + A connection object that implements the mailbox connection + interface. + encode: + A function that encodes an object into a bytes-like object. + decode: + A function that decodes an object from a bytes-like object. + """ + self.name = name + self._connection = connection + + if encode: + self.encode = encode + + if decode: + self.decode = decode + + def encode(self, value): + return value + + def decode(self, payload): + return payload + + def read(self): + """Reads the current value of the mailbox. + + Returns: + The decoded value or ``None`` if the mailbox has never received + a value. + """ + data = self._connection.read_from_mailbox(self.name) + if data is None: + return None + return self.decode(data) + + def send(self, value, destination=None): + """Sends a value to remote mailboxes with the same name as this + mailbox. + + Arguments: + value: The value to send. + destination: The name or address of a specific device or ``None`` + to broadcast to all connected devices. + """ + data = self.encode(value) + self._connection.send_to_mailbox(destination, self.name, data) + + def wait(self): + """Waits for the mailbox to receive a message.""" + self._connection.wait_for_mailbox_update(self.name) + + def wait_new(self): + """Waits for the mailbox to receive a message that is different from + the current contents of the mailbox. + + Returns: + The new value. (Same as return value of :meth:`read`.) + """ + old = self.read() + while True: + self.wait() + new = self.read() + if new != old: + return new + + +class LogicMailbox(Mailbox): + """:class:`Mailbox` that holds a logic or boolean value. + + This is compatible with the "logic" message blocks in the standard + EV3 firmware. + """ + + def encode(self, value): + return b'\x01' if value else b'\x00' + + def decode(self, payload): + return bool(payload[0]) + + +class NumericMailbox(Mailbox): + """:class:`Mailbox` that holds a numeric or floating point value. + + This is compatible with the "numeric" message blocks in the standard + EV3 firmware. + """ + + def encode(self, value): + return pack(' Bluetooth > Start Scan. +- Scroll down the list and choose your SPIKE hub. +- No need to pair or connect! Just write down the address you see. diff --git a/examples/ev3/bluetooth_read_spike/connection.py b/examples/ev3/bluetooth_read_spike/connection.py new file mode 100644 index 0000000..d30eb74 --- /dev/null +++ b/examples/ev3/bluetooth_read_spike/connection.py @@ -0,0 +1,80 @@ + +from uctypes import addressof, sizeof, struct +from usocket import socket, SOCK_STREAM + +from _thread import start_new_thread + +from pybricks.bluetooth import ( + str2ba, + sockaddr_rc, + AF_BLUETOOTH, + BTPROTO_RFCOMM +) +from pybricks.tools import wait, StopWatch + + +def get_bluetooth_rfcomm_socket(address, channel): + addr_data = bytearray(sizeof(sockaddr_rc)) + addr = struct(addressof(addr_data), sockaddr_rc) + addr.rc_family = AF_BLUETOOTH + str2ba(address, addr.rc_bdaddr) + addr.rc_channel = channel + + sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM) + sock.connect(addr_data) + return sock + + +class SpikePrimeStreamReader(): + def __init__(self, address): + + try: + self.sock = get_bluetooth_rfcomm_socket(address, 1) + except OSError as e: + print("Turn on Bluetooth on the EV3 and on SPIKE.") + raise e + + self._values = None + + start_new_thread(self.reader, ()) + + watch = StopWatch() + while watch.time() < 2000: + if self.values() is not None: + return + wait(100) + raise IOError("No data received") + + def disconnect(self): + self.sock.close() + + def reader(self): + while True: + try: + raw = self.sock.recv(1024) + except OSError: + break + try: + data = eval(raw) + if data['m'] == 0: + self._values = data['p'] + except (SyntaxError, KeyError): + pass + + def values(self): + return self._values + + def device(self, port): + if 'A' <= port <= 'F': + return self.values()[ord(port)-ord('A')][1] + else: + raise ValueError + + def acceleration(self): + return self.values()[6] + + def gyro(self): + return self.values()[7] + + def orientation(self): + return self.values()[8] diff --git a/examples/ev3/bluetooth_read_spike/main.py b/examples/ev3/bluetooth_read_spike/main.py new file mode 100644 index 0000000..901f215 --- /dev/null +++ b/examples/ev3/bluetooth_read_spike/main.py @@ -0,0 +1,17 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.hubs import EV3Brick +from pybricks.tools import wait + +from connection import SpikePrimeStreamReader + +# Beep! +ev3 = EV3Brick() +ev3.speaker.beep() + +# Create the connection. See README.md to find the address for your SPIKE hub. +spike = SpikePrimeStreamReader('F4:84:4C:AA:C8:A4') + +# Now you can simply read values! +for i in range(100): + print(spike.values()) + wait(100) diff --git a/examples/ev3/bluetooth_read_spike/rover.py b/examples/ev3/bluetooth_read_spike/rover.py new file mode 100644 index 0000000..f6f8dc2 --- /dev/null +++ b/examples/ev3/bluetooth_read_spike/rover.py @@ -0,0 +1,28 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.hubs import EV3Brick +from pybricks.tools import wait +from pybricks.ev3devices import Motor +from pybricks.robotics import DriveBase +from pybricks.parameters import Port + +from connection import SpikePrimeStreamReader + +# Beep! +ev3 = EV3Brick() +ev3.speaker.beep() + +# Create the connection. See README.md to find the address for your SPIKE hub. +spike = SpikePrimeStreamReader('F4:84:4C:AA:C8:A4') + +# Initialize the motors and drive base +left_motor = Motor(Port.B) +right_motor = Motor(Port.C) +robot = DriveBase(left_motor, right_motor, wheel_diameter=55.5, axle_track=104) + +while True: + # Read the orientation + yaw, pitch, roll = spike.orientation() + + # Set speed and turn rate based on orientation + robot.drive(-pitch*6, roll*2) + wait(20) diff --git a/examples/ev3/bluetooth_server/.gitignore b/examples/ev3/bluetooth_server/.gitignore new file mode 100644 index 0000000..9b5f630 --- /dev/null +++ b/examples/ev3/bluetooth_server/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +venv/ diff --git a/examples/ev3/bluetooth_server/.vscode/extensions.json b/examples/ev3/bluetooth_server/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/bluetooth_server/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/bluetooth_server/.vscode/launch.json b/examples/ev3/bluetooth_server/.vscode/launch.json new file mode 100644 index 0000000..167c178 --- /dev/null +++ b/examples/ev3/bluetooth_server/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/server.py" + } + ] +} diff --git a/examples/ev3/bluetooth_server/.vscode/settings.json b/examples/ev3/bluetooth_server/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/bluetooth_server/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/bluetooth_server/server.py b/examples/ev3/bluetooth_server/server.py new file mode 100644 index 0000000..9f325ee --- /dev/null +++ b/examples/ev3/bluetooth_server/server.py @@ -0,0 +1,23 @@ +#!/usr/bin/env pybricks-micropython + +# Before running this program, make sure the client and server EV3 bricks are +# paired using Bluetooth, but do NOT connect them. The program will take care +# of establishing the connection. + +# The server must be started before the client! + +from pybricks.messaging import BluetoothMailboxServer, TextMailbox + +server = BluetoothMailboxServer() +mbox = TextMailbox('greeting', server) + +# The server must be started before the client! +print('waiting for connection...') +server.wait_for_connection() +print('connected!') + +# In this program, the server waits for the client to send the first message +# and then sends a reply. +mbox.wait() +print(mbox.read()) +mbox.send('hello to you!') diff --git a/examples/ev3/buttons/.gitignore b/examples/ev3/buttons/.gitignore new file mode 100644 index 0000000..9b5f630 --- /dev/null +++ b/examples/ev3/buttons/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +venv/ diff --git a/examples/ev3/buttons/.vscode/extensions.json b/examples/ev3/buttons/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/buttons/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/buttons/.vscode/launch.json b/examples/ev3/buttons/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/buttons/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/buttons/.vscode/settings.json b/examples/ev3/buttons/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/buttons/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/buttons/main.py b/examples/ev3/buttons/main.py new file mode 100644 index 0000000..5174985 --- /dev/null +++ b/examples/ev3/buttons/main.py @@ -0,0 +1,20 @@ +#!/usr/bin/env pybricks-micropython + +from pybricks.hubs import EV3Brick +from pybricks.tools import wait +from pybricks.parameters import Button + +# Initialize the EV3 +ev3 = EV3Brick() + +# Wait until any of the buttons are pressed +while not any(ev3.buttons.pressed()): + wait(10) + +# Do something if the left button is pressed +if Button.LEFT in ev3.buttons.pressed(): + print("The left button is pressed.") + +# Wait until all buttons are released +while any(ev3.buttons.pressed()): + wait(10) diff --git a/examples/ev3/buttons_quickstart/.gitignore b/examples/ev3/buttons_quickstart/.gitignore new file mode 100644 index 0000000..9b5f630 --- /dev/null +++ b/examples/ev3/buttons_quickstart/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +venv/ diff --git a/examples/ev3/buttons_quickstart/.vscode/extensions.json b/examples/ev3/buttons_quickstart/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/buttons_quickstart/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/buttons_quickstart/.vscode/launch.json b/examples/ev3/buttons_quickstart/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/buttons_quickstart/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/buttons_quickstart/.vscode/settings.json b/examples/ev3/buttons_quickstart/.vscode/settings.json new file mode 100644 index 0000000..466469b --- /dev/null +++ b/examples/ev3/buttons_quickstart/.vscode/settings.json @@ -0,0 +1,7 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false, + "ev3devBrowser.download.exclude": "{**/.*,**/*.svg}" +} diff --git a/examples/ev3/buttons_quickstart/buttons.png b/examples/ev3/buttons_quickstart/buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..232026b8ff0d0c13be2963415b18dfdca0df2f64 GIT binary patch literal 2651 zcmb_e2{)VD8kW{Pl_Q4AF@y?Qt|XKFOZL0lIxk5(0q7 z@o0Cva}*9w@Q)4RBM=B@LLBqBY+T+!dN*f( zBj53?J0Di&M-{b%7m=#+Q~IQk)%KpDFp=9hKctU~d%U!jO^I$rJ}SsH3n_ftAw%Gy z_82*|%)hK`L9FfpCfIK0pzC2p#~`V?WoN3Hm(mI8{hCCH>ZY2u{Gn)Dd_s!RWAsQl zT`Kt=MMPdJuuDL+G}{08D(DV_$uz8~squ@5uwxnwRv2YwW${lI42g**W|*aZ&#JA} z!sGGm=k{2v8Vm-b+`4sQ)%c>)T~8g0;9$+J?(U#M1wNRjW>InRbrZrD_6x3)HS`@@ zAtpJw6&vpKhU>^STwYm0CM5i3M%=62odUN6fwvHJ(nJo{unM9D@eBYkjn*?sqS_}nm9e7+g+yygo_xFib*49;Zb-6q(Lm5+?=r{R*9x|ESi1C0I z1w5o|YR*52nq?>l4O@{tb}2$aLeera-RK@`HI@#ZjY6Sv3JO@|=cC*Uv4pBuIuVD^ z#Ira}pAOD!L=2ESjkVYS5UiXY@QMDYMG}dm3WEvi`o5^x>Db)ZNT<uDcXR*aWA?%LAEKXMw}mey`Dq{G56~)H#`a*h2d5kN>?tOo|>9+aCXk5QkBIeBqn(ie_pD*`RAWYZE5fO z`^6N=tiQ`IQTYz`j*>_d*9;roK_@hirX5_}x@vB2KE~lp;%oEeb+IWa(~;FiCMMmz zy+SWvz7&>_xck$@KZ9rc-CJBR)5Y6cM?gTpBQ>U_gvMgAJi<+kj7oogyLV4@RAqk? zRa|jbLxi#vKB;fJvZC*yZ)Wy>Q9d~`GLrFAGBqWorX_gjLS|-W{MAm^dXvYs4Gky< z2dRpXh`$yWanl`X zl{|%>K~FC)+4f76ME1hMLP=Q})>N>_GBNQPHe4?aRl{Hu^Mqke&d&cBZR@U7K> z0-$OP#nmTlw$0OL&q`CLM*=Q1)Yo@SOq8faeL8#WTX*)cMhx81#ib{SKfgf9gq4() zIJ(MP{`|RzMTP|V=6|ZY;X~`4n^WzV&UurRlmzz34rNP9O0FbSQrXrGoRbX6QOY%A zB?JQDUSJW(#0@B-x&B0s8XQjH30uL=oH>)%Zh_m!M(uo=scmk?nX;lXGBV%_;(YMc zJySSb%D})thxL7Jtj<}E_BSH=tDV7l>X)g<7wI$PlI*s$17d}Fn$IvHLnkyUD%*!v zxlLc6?Kp)Ph)7LMl{@%e?@27=i=OKQz2ahtVIS7l3&+M>xB*foVv>@q7pXtMUWJM5 z&cBt!-@kv~*sB^}HTucH-93b7?UU?;W>cxugxw8jOSy4w>cY}ez>lwMdChfs6p-q< zb6{Cn*=PbG*i_U*waGOfxC}K99%#Q{h9L#hmzP6;PW6AsyxNF?8gA|EV1j})7z{>9 zBdwkS^6S1SQCnAMiAD=lRaG@cYNIEHL(TymjJC7{d3t(EDJcy^$SwXc`zAL(ALZ@+ z>&@(JM_=DU;OgId@?^YuCv%b^+gZVF1i8`#|9Y<7*(b8QN<*tGcHI!e>1v_AbUrJsc5SB^d9n$BIA2TzB zjxm%`j)Iw>($doSpL3KcVR?piwIz{grmwH>URb4|tE=nc>UuIBb5^YDhPYjC%FplD zDiDdqJT1od))w;eW!aq{*}}*5;Yx8pT>z6Jx-mN9_>BnlfH!nHJ+H}D z+6x2KO+P%}{(jlqQZ=fIF~*0#-KTJV9$OxNguwySoKF0i^luwd8l7Q(TKGSfB?Afb ze)N2JXLt80XMiSBl>hthqiy?EcR3Am0GTFi%w^07s`tpbHG7wi@2lg#k)tyPi~ehP i4x|6a|NNhqyDBz + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/examples/ev3/buttons_quickstart/main.py b/examples/ev3/buttons_quickstart/main.py new file mode 100644 index 0000000..23116fe --- /dev/null +++ b/examples/ev3/buttons_quickstart/main.py @@ -0,0 +1,27 @@ +#!/usr/bin/env pybricks-micropython + +from pybricks.hubs import EV3Brick +from pybricks.parameters import Button + +from menu import wait_for_button + +# Initialize the EV3. +ev3 = EV3Brick() + +while True: + # Show the menu and wait for one button to be selected. + button = wait_for_button(ev3) + + # Now you can do something, based on which button was pressed. + + # In this demo, we just play a different sound for each button. + if button == Button.LEFT: + ev3.speaker.beep(200) + elif button == Button.RIGHT: + ev3.speaker.beep(400) + elif button == Button.UP: + ev3.speaker.beep(600) + elif button == Button.DOWN: + ev3.speaker.beep(800) + elif button == Button.CENTER: + ev3.speaker.beep(1000) diff --git a/examples/ev3/buttons_quickstart/menu.py b/examples/ev3/buttons_quickstart/menu.py new file mode 100644 index 0000000..e3789a3 --- /dev/null +++ b/examples/ev3/buttons_quickstart/menu.py @@ -0,0 +1,30 @@ +def wait_for_button(ev3): + """ + This function shows a picture of the buttons on the EV3 screen. + + Then it waits until you press a button. + + It returns which button was pressed. + """ + + # Show a picture of the buttons on the screen. + ev3.screen.load_image('buttons.png') + + # Tip: add text or icons to the image to help you + # remember what each button will do in your program. + + # Wait for a single button to be pressed and save the result. + pressed = [] + while len(pressed) != 1: + pressed = ev3.buttons.pressed() + button = pressed[0] + + # Print which button was pressed + ev3.screen.draw_text(2, 100, button) + + # Now wait for the button to be released. + while any(ev3.buttons.pressed()): + pass + + # Return which button was pressed. + return button diff --git a/examples/ev3/datalog/.gitignore b/examples/ev3/datalog/.gitignore new file mode 100644 index 0000000..00f2d38 --- /dev/null +++ b/examples/ev3/datalog/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.venv/ diff --git a/examples/ev3/datalog/.vscode/extensions.json b/examples/ev3/datalog/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/datalog/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/datalog/.vscode/launch.json b/examples/ev3/datalog/.vscode/launch.json new file mode 100644 index 0000000..d933aeb --- /dev/null +++ b/examples/ev3/datalog/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py", + "interactiveTerminal": false + } + ] +} diff --git a/examples/ev3/datalog/.vscode/settings.json b/examples/ev3/datalog/.vscode/settings.json new file mode 100644 index 0000000..b0968c1 --- /dev/null +++ b/examples/ev3/datalog/.vscode/settings.json @@ -0,0 +1,7 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false, + "python.languageServer": "None" +} diff --git a/examples/ev3/datalog/main.py b/examples/ev3/datalog/main.py new file mode 100644 index 0000000..a35f9b3 --- /dev/null +++ b/examples/ev3/datalog/main.py @@ -0,0 +1,34 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.ev3devices import Motor +from pybricks.parameters import Port +from pybricks.tools import DataLog, StopWatch, wait + +# Create a data log file in the project folder on the EV3 Brick. +# * By default, the file name contains the current date and time, for example: +# log_2020_02_13_10_07_44_431260.csv +# * You can optionally specify the titles of your data columns. For example, +# if you want to record the motor angles at a given time, you could do: +data = DataLog('time', 'angle') + +# Initialize a motor and make it move +wheel = Motor(Port.B) +wheel.run(500) + +# Start a stopwatch to measure elapsed time +watch = StopWatch() + +# Log the time and the motor angle 10 times +for i in range(10): + # Read angle and time + angle = wheel.angle() + time = watch.time() + + # Each time you use the log() method, a new line with data is added to + # the file. You can add as many values as you like. + # In this example, we save the current time and motor angle: + data.log(time, angle) + + # Wait some time so the motor can move a bit + wait(100) + +# You can now upload your file to your computer diff --git a/examples/ev3/datalog_extra/.gitignore b/examples/ev3/datalog_extra/.gitignore new file mode 100644 index 0000000..00f2d38 --- /dev/null +++ b/examples/ev3/datalog_extra/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.venv/ diff --git a/examples/ev3/datalog_extra/.vscode/extensions.json b/examples/ev3/datalog_extra/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/datalog_extra/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/datalog_extra/.vscode/launch.json b/examples/ev3/datalog_extra/.vscode/launch.json new file mode 100644 index 0000000..d933aeb --- /dev/null +++ b/examples/ev3/datalog_extra/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py", + "interactiveTerminal": false + } + ] +} diff --git a/examples/ev3/datalog_extra/.vscode/settings.json b/examples/ev3/datalog_extra/.vscode/settings.json new file mode 100644 index 0000000..b0968c1 --- /dev/null +++ b/examples/ev3/datalog_extra/.vscode/settings.json @@ -0,0 +1,7 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false, + "python.languageServer": "None" +} diff --git a/examples/ev3/datalog_extra/main.py b/examples/ev3/datalog_extra/main.py new file mode 100644 index 0000000..b2b15e0 --- /dev/null +++ b/examples/ev3/datalog_extra/main.py @@ -0,0 +1,15 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.parameters import Color +from pybricks.tools import DataLog + +# Create a data log file called my_file.txt +data = DataLog('time', 'angle', name='my_file', timestamp=False, extension='txt') + +# The log method uses the print() method to add a line of text. +# So, you can do much more than saving numbers. For example: +data.log('Temperature', 25) +data.log('Sunday', 'Monday', 'Tuesday') +data.log({'Kiwi': Color.GREEN}, {'Banana': Color.YELLOW}) + +# You can upload the file to your computer, but you can also print the data: +print(data) diff --git a/examples/ev3/ev3devsensor/.gitignore b/examples/ev3/ev3devsensor/.gitignore new file mode 100644 index 0000000..9b5f630 --- /dev/null +++ b/examples/ev3/ev3devsensor/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +venv/ diff --git a/examples/ev3/ev3devsensor/.vscode/extensions.json b/examples/ev3/ev3devsensor/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/ev3devsensor/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/ev3devsensor/.vscode/launch.json b/examples/ev3/ev3devsensor/.vscode/launch.json new file mode 100644 index 0000000..7dc1149 --- /dev/null +++ b/examples/ev3/ev3devsensor/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Main Example", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + }, + { + "name": "Class Example", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/class_example.py" + } + ] +} diff --git a/examples/ev3/ev3devsensor/.vscode/settings.json b/examples/ev3/ev3devsensor/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/ev3devsensor/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/ev3devsensor/class_example.py b/examples/ev3/ev3devsensor/class_example.py new file mode 100644 index 0000000..95dfe40 --- /dev/null +++ b/examples/ev3/ev3devsensor/class_example.py @@ -0,0 +1,46 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.parameters import Port +from pybricks.iodevices import Ev3devSensor + + +class MySensor(Ev3devSensor): + """Example of extending the Ev3devSensor class.""" + + def __init__(self, port): + """Initialize the sensor.""" + + # Initialize the parent class. + super().__init__(port) + + # Get the sysfs path. + self.path = '/sys/class/lego-sensor/sensor' + str(self.sensor_index) + + def get_modes(self): + """Get a list of mode strings so we don't have to look them up.""" + + # The path of the modes file. + modes_path = self.path + '/modes' + + # Open the modes file. + with open(modes_path, 'r') as m: + + # Read the contents. + contents = m.read() + + # Strip the newline symbol, and split at every space symbol. + return contents.strip().split(' ') + + +# Initialize the sensor +sensor = MySensor(Port.S3) + +# Show where this sensor can be found +print(sensor.path) + +# Print the available modes +modes = sensor.get_modes() +print(modes) + +# Read mode 0 of this sensor +val = sensor.read(modes[0]) +print(val) diff --git a/examples/ev3/ev3devsensor/main.py b/examples/ev3/ev3devsensor/main.py new file mode 100644 index 0000000..58a6d7c --- /dev/null +++ b/examples/ev3/ev3devsensor/main.py @@ -0,0 +1,19 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.parameters import Port +from pybricks.tools import wait +from pybricks.iodevices import Ev3devSensor + +# Initialize an Ev3devSensor. +# In this example we use the +# LEGO MINDSTORMS EV3 Color Sensor. +sensor = Ev3devSensor(Port.S3) + +while True: + # Read the raw RGB values + r, g, b = sensor.read('RGB-RAW') + + # Print results + print('R: {0}\t G: {1}\t B: {2}'.format(r, g, b)) + + # Wait + wait(200) diff --git a/examples/ev3/getting_started/.gitignore b/examples/ev3/getting_started/.gitignore new file mode 100644 index 0000000..9b5f630 --- /dev/null +++ b/examples/ev3/getting_started/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +venv/ diff --git a/examples/ev3/getting_started/.vscode/extensions.json b/examples/ev3/getting_started/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/getting_started/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/getting_started/.vscode/launch.json b/examples/ev3/getting_started/.vscode/launch.json new file mode 100644 index 0000000..d933aeb --- /dev/null +++ b/examples/ev3/getting_started/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py", + "interactiveTerminal": false + } + ] +} diff --git a/examples/ev3/getting_started/.vscode/settings.json b/examples/ev3/getting_started/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/getting_started/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/getting_started/main.py b/examples/ev3/getting_started/main.py new file mode 100644 index 0000000..05e48c3 --- /dev/null +++ b/examples/ev3/getting_started/main.py @@ -0,0 +1,23 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.hubs import EV3Brick +from pybricks.ev3devices import Motor +from pybricks.parameters import Port + +# Create your objects here + +# Initialize the EV3 Brick. +ev3 = EV3Brick() + +# Initialize a motor at port B. +test_motor = Motor(Port.B) + +# Write your program here + +# Play a sound. +ev3.speaker.beep() + +# Run the motor up to 500 degrees per second. To a target angle of 90 degrees. +test_motor.run_target(500, 90) + +# Play another beep sound. +ev3.speaker.beep(frequency=1000, duration=500) diff --git a/examples/ev3/i2c_basics/.gitignore b/examples/ev3/i2c_basics/.gitignore new file mode 100644 index 0000000..9b5f630 --- /dev/null +++ b/examples/ev3/i2c_basics/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +venv/ diff --git a/examples/ev3/i2c_basics/.vscode/extensions.json b/examples/ev3/i2c_basics/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/i2c_basics/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/i2c_basics/.vscode/launch.json b/examples/ev3/i2c_basics/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/i2c_basics/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/i2c_basics/.vscode/settings.json b/examples/ev3/i2c_basics/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/i2c_basics/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/i2c_basics/main.py b/examples/ev3/i2c_basics/main.py new file mode 100644 index 0000000..37d412f --- /dev/null +++ b/examples/ev3/i2c_basics/main.py @@ -0,0 +1,23 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.hubs import EV3Brick +from pybricks.iodevices import I2CDevice +from pybricks.parameters import Port + +# Initialize the EV3 +ev3 = EV3Brick() + +# Initialize I2C Sensor +device = I2CDevice(Port.S2, 0xD2 >> 1) + +# Read one byte from the device. +# For this device, we can read the Who Am I +# register (0x0F) for the expected value: 211. +if 211 not in device.read(0x0F): + raise OSError("Device is not attached") + +# To write data, create a bytes object of one +# or more bytes. For example: +# data = bytes((1, 2, 3)) + +# Write one byte (value 0x08) to register 0x22 +device.write(0x22, bytes((0x08,))) diff --git a/examples/ev3/i2c_extra/.gitignore b/examples/ev3/i2c_extra/.gitignore new file mode 100644 index 0000000..9b5f630 --- /dev/null +++ b/examples/ev3/i2c_extra/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +venv/ diff --git a/examples/ev3/i2c_extra/.vscode/extensions.json b/examples/ev3/i2c_extra/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/i2c_extra/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/i2c_extra/.vscode/launch.json b/examples/ev3/i2c_extra/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/i2c_extra/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/i2c_extra/.vscode/settings.json b/examples/ev3/i2c_extra/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/i2c_extra/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/i2c_extra/main.py b/examples/ev3/i2c_extra/main.py new file mode 100644 index 0000000..807ea2f --- /dev/null +++ b/examples/ev3/i2c_extra/main.py @@ -0,0 +1,35 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.hubs import EV3Brick +from pybricks.iodevices import I2CDevice +from pybricks.parameters import Port + +# Initialize the EV3 +ev3 = EV3Brick() + +# Initialize I2C Sensor +device = I2CDevice(Port.S2, 0xD2 >> 1) + +# Recommended for reading +result, = device.read(reg=0x0F, length=1) + +# Read 1 byte from no particular register: +device.read(reg=None, length=1) + +# Read 0 bytes from no particular register: +device.read(reg=None, length=0) + +# I2C write operations consist of a register byte followed +# by a series of data bytes. Depending on your device, you +# can choose to skip the register or data as follows: + +# Recommended for writing: +device.write(reg=0x22, data=b'\x08') + +# Write 1 byte to no particular register: +device.write(reg=None, data=b'\x08') + +# Write 0 bytes to a particular register: +device.write(reg=0x08, data=None) + +# Write 0 bytes to no particular register: +device.write(reg=None, data=None) diff --git a/examples/ev3/light_color/.gitignore b/examples/ev3/light_color/.gitignore new file mode 100644 index 0000000..9b5f630 --- /dev/null +++ b/examples/ev3/light_color/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +venv/ diff --git a/examples/ev3/light_color/.vscode/extensions.json b/examples/ev3/light_color/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/light_color/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/light_color/.vscode/launch.json b/examples/ev3/light_color/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/light_color/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/light_color/.vscode/settings.json b/examples/ev3/light_color/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/light_color/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/light_color/main.py b/examples/ev3/light_color/main.py new file mode 100644 index 0000000..69f3351 --- /dev/null +++ b/examples/ev3/light_color/main.py @@ -0,0 +1,17 @@ +#!/usr/bin/env pybricks-micropython + +from pybricks.hubs import EV3Brick +from pybricks.tools import wait +from pybricks.parameters import Color + +# Initialize the EV3 +ev3 = EV3Brick() + +# Turn on a red light +ev3.light.on(Color.RED) + +# Wait +wait(1000) + +# Turn the light off +ev3.light.off() diff --git a/examples/ev3/ps4/.gitignore b/examples/ev3/ps4/.gitignore new file mode 100644 index 0000000..00f2d38 --- /dev/null +++ b/examples/ev3/ps4/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.venv/ diff --git a/examples/ev3/ps4/.vscode/extensions.json b/examples/ev3/ps4/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/ps4/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/ps4/.vscode/launch.json b/examples/ev3/ps4/.vscode/launch.json new file mode 100644 index 0000000..d933aeb --- /dev/null +++ b/examples/ev3/ps4/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py", + "interactiveTerminal": false + } + ] +} diff --git a/examples/ev3/ps4/.vscode/settings.json b/examples/ev3/ps4/.vscode/settings.json new file mode 100644 index 0000000..b0968c1 --- /dev/null +++ b/examples/ev3/ps4/.vscode/settings.json @@ -0,0 +1,7 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false, + "python.languageServer": "None" +} diff --git a/examples/ev3/ps4/main.py b/examples/ev3/ps4/main.py new file mode 100644 index 0000000..fd82bda --- /dev/null +++ b/examples/ev3/ps4/main.py @@ -0,0 +1,145 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.ev3devices import Motor +from pybricks.parameters import Port + +import struct + +# This program uses the two PS4 sticks to control two EV3 Large Servo Motors +# using tank like controls. For a full map of all PS4 buttons, trackpad, and +# motion checkout: https://github.com/codeadamca/python-connect-ps4 + +# Initialize EV3 motors +left_motor = Motor(Port.B) +right_motor = Motor(Port.C) +left_speed = 0 +right_speed = 0 + +# Locate the event file you want to react to, on my setup the PS4 controller +# button events are located in /dev/input/event4 +infile_path = "/dev/input/event4" +in_file = open(infile_path, "rb") + +# Define the format the event data will be read. +# https://docs.python.org/3/library/struct.html#format-characters +FORMAT = 'llHHi' +EVENT_SIZE = struct.calcsize(FORMAT) +event = in_file.read(EVENT_SIZE) + + +# A helper function for converting stick values (0 to 255) to more usable +# numbers (-100 to 100) +def scale(val, src, dst): + + result = (float(val - src[0]) / (src[1] - src[0])) + result = result * (dst[1] - dst[0]) + dst[0] + return result + +# Create a loop to react to events +# This loop reacte to all main PS4 button and stick events. I have left out +# buttons like share and options, but can easily be added in by referring +# to the table at: https://github.com/codeadamca/python-connect-ps4 + + +while event: + + # Place event data into variables + (tv_sec, tv_usec, ev_type, code, value) = struct.unpack(FORMAT, event) + + # If a button was pressed or released + if ev_type == 1: + + # React to the X button + if code == 304 and value == 0: + print("The X button was released") + elif code == 304 and value == 1: + print("The X button was pressed") + + # React to the Circle button + elif code == 305 and value == 0: + print("The Circle button was released") + elif code == 305 and value == 1: + print("The Circle button was pressed") + + # React to the Triangle button + elif code == 307 and value == 0: + print("The Triangle button was released") + elif code == 307 and value == 1: + print("The Triangle button was pressed") + + # React to the Square button + elif code == 308 and value == 0: + print("The Square button was released") + elif code == 308 and value == 1: + print("The Square button was pressed") + + # React to the L1 button + elif code == 310 and value == 0: + print("The L1 button was released") + elif code == 310 and value == 1: + print("The L1 button was pressed") + + # React to the R1 button + elif code == 311 and value == 0: + print("The R1 button was released") + elif code == 311 and value == 1: + print("The R1 button was pressed") + + # React to the L2 button + elif code == 312 and value == 0: + print("The L2 button was released") + elif code == 312 and value == 1: + print("The L2 button was pressed") + + # React to the R2 button + elif code == 313 and value == 0: + print("The R2 button was released") + elif code == 313 and value == 1: + print("The R2 button was pressed") + + elif ev_type == 3: + + # The sticks often trigger non-stop events, comment this out if you are + # not using the sticks as part of your project, or it becomes hard to + # read other data + + # React to the left stick vertical + if code == 1: + print("The left stick vertical is at ", value) + left_speed = scale(value, (0, 255), (100, -100)) + + # React to the left stick horizontal + elif code == 0: + print("The left stick horizontal is at ", value) + + # React to the right stick vertical + elif code == 4: + print("The right stick vertical is at ", value) + right_speed = scale(value, (0, 255), (100, -100)) + + # React to the right stick horizontal + elif code == 3: + print("The right stick horizontal is at ", value) + + # React to the Directional pad + if code == 16 and value == -1: + print("The horizontal directional pad is left") + elif code == 16 and value == 1: + print("The horizontal directional pad is right") + elif code == 16 and value == 0: + print("The horizontal directional pad is released") + + elif code == 17 and value == -1: + print("The vertical directional pad is up") + elif code == 17 and value == 1: + print("The horizontal directional pad is down") + elif code == 17 and value == 0: + print("The horizontal directional pad is released") + + # Set motor speed + left_motor.dc(left_speed) + right_motor.dc(right_speed) + + # Read the next event + event = in_file.read(EVENT_SIZE) + +in_file.close() diff --git a/examples/ev3/rcx_touch/.gitignore b/examples/ev3/rcx_touch/.gitignore new file mode 100644 index 0000000..00f2d38 --- /dev/null +++ b/examples/ev3/rcx_touch/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.venv/ diff --git a/examples/ev3/rcx_touch/.vscode/extensions.json b/examples/ev3/rcx_touch/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/rcx_touch/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/rcx_touch/.vscode/launch.json b/examples/ev3/rcx_touch/.vscode/launch.json new file mode 100644 index 0000000..d933aeb --- /dev/null +++ b/examples/ev3/rcx_touch/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py", + "interactiveTerminal": false + } + ] +} diff --git a/examples/ev3/rcx_touch/.vscode/settings.json b/examples/ev3/rcx_touch/.vscode/settings.json new file mode 100644 index 0000000..b0968c1 --- /dev/null +++ b/examples/ev3/rcx_touch/.vscode/settings.json @@ -0,0 +1,7 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false, + "python.languageServer": "None" +} diff --git a/examples/ev3/rcx_touch/main.py b/examples/ev3/rcx_touch/main.py new file mode 100644 index 0000000..d2c512f --- /dev/null +++ b/examples/ev3/rcx_touch/main.py @@ -0,0 +1,21 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.hubs import EV3Brick +from pybricks.iodevices import AnalogSensor +from pybricks.parameters import Port, Color +from pybricks.tools import wait + + +class RCXTouchSensor(AnalogSensor): + def pressed(self): + return self.resistance() < 50*1000 + + +ev3 = EV3Brick() +btn = RCXTouchSensor(Port.S1) + +while True: + if btn.pressed(): + ev3.light.on(Color.ORANGE) + else: + ev3.light.off() + wait(10) diff --git a/examples/ev3/screen_draw/.gitignore b/examples/ev3/screen_draw/.gitignore new file mode 100644 index 0000000..00f2d38 --- /dev/null +++ b/examples/ev3/screen_draw/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.venv/ diff --git a/examples/ev3/screen_draw/.vscode/extensions.json b/examples/ev3/screen_draw/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/screen_draw/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/screen_draw/.vscode/launch.json b/examples/ev3/screen_draw/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/screen_draw/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/screen_draw/.vscode/settings.json b/examples/ev3/screen_draw/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/screen_draw/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/screen_draw/main.py b/examples/ev3/screen_draw/main.py new file mode 100644 index 0000000..ab98c0a --- /dev/null +++ b/examples/ev3/screen_draw/main.py @@ -0,0 +1,32 @@ +#!/usr/bin/env pybricks-micropython + +from pybricks.hubs import EV3Brick +from pybricks.tools import wait + + +# Initialize the EV3 +ev3 = EV3Brick() + + +# Draw a rectangle +ev3.screen.draw_box(10, 10, 40, 40) + +# Draw a solid rectangle +ev3.screen.draw_box(20, 20, 30, 30, fill=True) + +# Draw a rectangle with rounded corners +ev3.screen.draw_box(50, 10, 80, 40, 5) + +# Draw a circle +ev3.screen.draw_circle(25, 75, 20) + +# Draw a triangle using lines +x1, y1 = 65, 55 +x2, y2 = 50, 95 +x3, y3 = 80, 95 +ev3.screen.draw_line(x1, y1, x2, y2) +ev3.screen.draw_line(x2, y2, x3, y3) +ev3.screen.draw_line(x3, y3, x1, y1) + +# Wait some time to look at the shapes +wait(5000) diff --git a/examples/ev3/screen_extra/.gitignore b/examples/ev3/screen_extra/.gitignore new file mode 100644 index 0000000..00f2d38 --- /dev/null +++ b/examples/ev3/screen_extra/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.venv/ diff --git a/examples/ev3/screen_extra/.vscode/extensions.json b/examples/ev3/screen_extra/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/screen_extra/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/screen_extra/.vscode/launch.json b/examples/ev3/screen_extra/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/screen_extra/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/screen_extra/.vscode/settings.json b/examples/ev3/screen_extra/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/screen_extra/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/screen_extra/background.png b/examples/ev3/screen_extra/background.png new file mode 100644 index 0000000000000000000000000000000000000000..aae8020d5c9142741ea5fe7d84cfdcc7469aef8e GIT binary patch literal 3664 zcmaJ^2T&8;7GA)v2vR~*X;OcR0z#yyARP@wiu4Xj3xpz}8$|`AgOor3frKJLg3_fU zoe)DYVkpui0wP5qw7378dGqGYd-Lw>-8*y7xp(*O`ObH~jWL4hFrVQ)0{{TCp01_| zI1<1fb&3(Z3s@Cpfx~HET}yueI2Q7EXK>ROsRAcY2I$?>IyuL1hVzsX(kvhhT>nc? zQ{6Q9>q>6;-TUKw-FcyV8h2DW%b*TVg+du>K2R?Hb|q;!eyWEK%DEB-Mf@o_`P#_S z-0mmirZu_JvRvh%3QSnH{!A!0rS&1o(y09z&w!}xb7k&f{YQU!7i@2L?;gGp-@Kjo;jVf>a42vGrrK~z17B%k&)@?={PRgoAe)rBYb{8h6|dSR4dFU zhKFxYT9l8{e4(PQbMZ=(4?R32B_u3Ac#OL68Qs61iosxVa+=^%H~GKX+uP^m=2noG z^bHKe_AFC-H6wa@dg>7Keb1TsCd0RFX=)G;>@R z8#_A_aPs^`R&ECcUiZQ5{c582UC~tV>UGgBB)v$?Qw}@>j8#~3B{i~pczVVd z@^EuIkce7ZS^z62r>i3RqusJC#Ja|dA*!>plSDFx3{va;#Q-V$W}8>Z@aEkUKuStV z*j}BkFTZ*w?qABq35 z@|VTCo_Pdjk(hVuSEH1+w)XegS%%w{<7d6TR5>yMO&dchPOrfB?AbHmwvLWYz6)t| z^f(}y?&0F1Iq;ZL=O+vlVX<cNm-Q)B)r84T0(v_rydc6RoI&3dX&Bz+0TAfTi) z-r>4U9iks>PqAE9?b!%>^r%#$zyW`zudffpkxJ0=%h*^p=f!UR$YW90J;#m(8SC)g z=AD&KPENM2_2E1wC@-I?B|MKnf(tc;BqSvp!gkl^%!Ob$|HJ)Vpvr#{rd`Oh)J&;% zpK1s+cy%eGf2&705s1p9oK7cw|6FV^SKnYGb1i7V&HupzZot&SLY}sNNhK)h_vno8 z-S(JeY9kk*z&p6Mb~Vl|J|W@e*2sM)(HI}_Af30)NfLa|Zi1T#wV3+(UGtlQ;Zn7Z ztSiR8e0czfi;HKLNWHUd#2Sf16UxiWor}g~TlU$2g+a7??Sxh~i1b9jq5rkC(<`Io zXn|Aw5j%pwGNoFl=+cXh-#fF3Os%9s9Ue6logR`fi$b9ecV=0B5xDvItO+isfu`-r z&{w=J_y_GB9SqZ(OXTkr$uXGBimR~%0c#T{(U!;8B~(?vIpME{u%Z>c8Kbn~Ao20> z$mFiYyhxapvs@PU2T@sB762k+BmVhhsy7R8>h$RgH)z8t(NrHXgZZH$*zZdpf`2;! zJ^lU8n*u)622LKH(}0MG2*!m(r5+65VPR<9o{A)vNQ8%n&q26kY*^v(JJV@t9FmpT zzX9+!D%s{Qz{~LXUNRK(iEy+>`XdyaB$$iFu)Ks+nqQieRlgO7wU(~y=qZu zr`Bc^pEqR?OUQ>lr`9)ER=Y7bE+Y1K`~ai!(bWs;A@t2hZ_*AA4@*kKqczkcHl_m3 zC7fkuE+({$jgAH`4DetUxn%A3`(;~#>*TF+xq(S0bO0)wfELa*OZl&fmSDc z62B(Fp$!Zq{XPyRZBu6y7Bp7lJprP;tgMViqk-(x^$U?e{4i1H=j`h0>g~M((o8QO zN?^Nh$O`YIWovs0xFRN&Xdz?y>1E4cUgRN#O06(2&kJ3>QOPy25`-RH*v)?OhQ1;!CH(hwReO>DlnB?9LhB)w%()D-GeQ4 zMJR}<#vE&`vc8sZNkzL~wBkS$;(yjEwDK`x^M^6;GA8B%Pu+G@sF*()d#}|mN2A~& z9PX}ExVv0U1g5jxF$L*UTG!~Ux{&wnZa&&NI(oO8>gqD7sUC2+m>&xe)!wcV^jI$I z?iI6YEcW^9dy+HPu!MXW8+FzpjG6(q1gs3p7z=fE24GD&S4LR)DRs{E*W^cV8q5*l zP*+o5u?IUx54tsRUKe%DXNAbJt1hEuX1%?=qNz({!&|Q7>u=w_-Q8GZD!g(}!@?p% zqhK0|S+xyN&fQTJ#}*!^R#9@BWAtyL-LuhXb%$OwyjkycS3t40i0UUR$oUsfy>@qU z9BBmxQxSXKSeAqto{`tDUxVR{)=19FGbAmu+}Z~KFoy|8hQhEjS$Auky3POsGvcu@ z%L1dcjEuOc&JBP#Vo-1MZe^ktB-Hx~22ES#mCedqO3}K)5-?dn07QhE8g(84M){hT za-nfaLqm4g`z#-U*iv@KaVtoiN+dKHkH3b<1c|zQ)Fbva5u^4qKsiIkmUi@X@+K=U zZ-YxO8;-1(AZ4V`=s7L}^b8GM=Ho*v!sdQfw)l8@#>K=?nvn9g{bpun_XW2j3Akgr z)ecdC#3d z><8+rB!fsi*xOEJ4y0Kpk%yjEStlmNk1(A)541Li@0~b#68D~+(j2Y=ytQq7O|R0P z-^@J9Jr!3)*?Fc!dvR2BQSuSX5M!Hoah2mywYHCta*wXdQOiiztq$r}j!~AgV?d_m$+1w2HuK(ln z*RNJ~c9*%hx*vZ3JU(t=ZjLo6{rvfJ58Os(e0Z2udXJNn6A~vPA<^sq?(6VyQvdw= z&u^&Zqs7HV`Pfc5tA$-hpEen<1?|dlrq;gnzi?xWTi@#a0|NsuT)0rg3JJs-1TRNi zJ%g_A9T+&r!ctjLaj-RRkLzPJ+p&*N0ELitv@Om!c!1b%iqbEpgQbB%Kuk<$&D@x5 z2rGK?h7kY@I}fL`1BdTAj{SE>t#8J;-9Hm>reB&lFtJ{QjHG0WezBBY^b+UgM*de| zdR}4Eb9590<`x!UHJ_!!#n!vH>}^^i4!|L7KHY*l@P`8R+eMbbsx0(qxrLaBNMKM< z#MY?AlK`QPjt>9DAy*3sEZ^A1FZOTHBx@5NWvUX1S@P}=ABsD`T#gP8z=}{>T1vci zq*|!ddg-$8aV+jSiA1uh7<0nss60*}Nn^tQP}0&sdW}FRiUF`Wkklk(WM22r7d0>o zV|D$s8X}&NLY^6cqKAVcU~Rf>a&i*r(Wo3}VPSz!)Wr8m4Da255{4sNU5w4lwA^`+ zvI@NStgN!ToOb6@4foY*>w;FY?}|Eyx5vlL62F{@0>@}*EU!#?y3Sa_^4-tt2y0CF2tOi zoZib~$&;41y_=|wv{KuqV0>}0h@hZ4>oKA$DeUV_i`!GmieYzD19TePe#8_Ed zTf^b-urO5#j=@tVh7}(_=I;A3ScluqHGHLR_2fQ`276V zhYBfkSI1}(N$t*;Yf3&?Nym}hW@BEy1l9Ug-gx$-*%tPc=r#u^Von#-WMoO}StTWY zucMV0AR0l2e*p@mwV4hjpKtl1an#1g6J9m@`(aqJTkZYO)^=x%YnuX?YsDr@TlD1Q z3n}Y*jy`@{G&At01Vn|L{^&W=V5utqvn|nst9Sq0)zwYXy;4z8VJCaY@`tVw$ RI`}sT=xM<;-)T6Y{sA#_7jpmr literal 0 HcmV?d00001 diff --git a/examples/ev3/screen_extra/main.py b/examples/ev3/screen_extra/main.py new file mode 100644 index 0000000..b8e6462 --- /dev/null +++ b/examples/ev3/screen_extra/main.py @@ -0,0 +1,104 @@ +#!/usr/bin/env pybricks-micropython + +import math + +from pybricks.hubs import EV3Brick +from pybricks.parameters import Color +from pybricks.tools import wait +from pybricks.media.ev3dev import Font, Image + + +# Initialize the EV3 +ev3 = EV3Brick() + + +# SPLIT SCREEN ################################################################ + +# Make a sub-image for the left half of the screen +left = Image(ev3.screen, sub=True, x1=0, y1=0, + x2=ev3.screen.width // 2 - 1, y2=ev3.screen.height - 1) + +# Make a sub-image for the right half of the screen +right = Image(ev3.screen, sub=True, x1=ev3.screen.width // 2, y1=0, + x2=ev3.screen.width - 1, y2=ev3.screen.height - 1) + +# Use a monospaced font so that text is vertically aligned when we print +right.set_font(Font(size=8, monospace=True)) + + +# Graphing y = sin(x) +def f(x): + return math.sin(x) + + +for t in range(200): + # Graph on left side + + # Scale t to x-axis and compute y values + x0 = (t - 1) * 2 * math.pi / left.width + y0 = f(x0) + x1 = t * 2 * math.pi / left.width + y1 = f(x1) + + # Scale y values to screen coordinates + sy0 = (-y0 + 1) * left.height / 2 + sy1 = (-y1 + 1) * left.height / 2 + + # Shift the current graph to the left one pixel + left.draw_image(-1, 0, left) + # Fill the last column with white to erase the previous plot point + left.draw_line(left.width - 1, 0, left.width - 1, left.height - 1, 1, Color.WHITE) + # Draw the new value of the graph in the last column + left.draw_line(left.width - 2, int(sy0), left.width - 1, int(sy1), 3) + + # Print every 10th value on right side + if t % 10 == 0: + right.print('{:10.2f}{:10.2f}'.format(x1, y1)) + + wait(100) + + +# SPRITE ANIMATION ############################################################ + +# Copy of screen for double-buffering +buf = Image(ev3.screen) + +# Load images from file +bg = Image('background.png') +sprite = Image('sprite.png') + +# Number of cells in each sprite animation +NUM_CELLS = 8 + +# Each cell in the sprite is 75 x 100 pixels +CELL_WIDTH, CELL_HEIGHT = 75, 100 + +# Get sub-images for each individual cell +# This is more efficient that loading individual images +walk_right = [Image(sprite, sub=True, x1=x * CELL_WIDTH, y1=0, + x2=(x + 1) * CELL_WIDTH - 1, y2=CELL_HEIGHT - 1) + for x in range(NUM_CELLS)] +walk_left = [Image(sprite, sub=True, x1=x * CELL_WIDTH, y1=CELL_HEIGHT, + x2=(x + 1) * CELL_WIDTH - 1, y2=2 * CELL_HEIGHT - 1) + for x in range(NUM_CELLS)] + + +# Walk from left to right +for x in range(-100, 200, 2): + # Start with the background image + buf.draw_image(0, 0, bg) + # Draw the current sprite - purple is treated as transparent + buf.draw_image(x, 5, walk_right[x // 5 % NUM_CELLS], Color.PURPLE) + # Copy the double-buffer to the screen + ev3.screen.draw_image(0, 0, buf) + # 20 frames per second + wait(50) + +# Walk from right to left +for x in range(200, -100, -2): + buf.draw_image(0, 0, bg) + buf.draw_image(x, 5, walk_left[x // 5 % NUM_CELLS], Color.PURPLE) + ev3.screen.draw_image(0, 0, buf) + wait(50) + +wait(1000) diff --git a/examples/ev3/screen_extra/sprite.png b/examples/ev3/screen_extra/sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..33057ed5e2b0942e7f381c2cce9555023b2371dd GIT binary patch literal 40847 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 z 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 literal 0 HcmV?d00001 diff --git a/examples/ev3/screen_image/.gitignore b/examples/ev3/screen_image/.gitignore new file mode 100644 index 0000000..00f2d38 --- /dev/null +++ b/examples/ev3/screen_image/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.venv/ diff --git a/examples/ev3/screen_image/.vscode/extensions.json b/examples/ev3/screen_image/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/screen_image/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/screen_image/.vscode/launch.json b/examples/ev3/screen_image/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/screen_image/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/screen_image/.vscode/settings.json b/examples/ev3/screen_image/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/screen_image/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/screen_image/main.py b/examples/ev3/screen_image/main.py new file mode 100644 index 0000000..2d6870c --- /dev/null +++ b/examples/ev3/screen_image/main.py @@ -0,0 +1,20 @@ +#!/usr/bin/env pybricks-micropython + +from pybricks.hubs import EV3Brick +from pybricks.tools import wait +from pybricks.media.ev3dev import Image, ImageFile + +# It takes some time to load images from the SD card, so it is best to load +# them once at the beginning of a program like this: +ev3_img = Image(ImageFile.EV3_ICON) + + +# Initialize the EV3 +ev3 = EV3Brick() + + +# Show an image +ev3.screen.load_image(ev3_img) + +# Wait some time to look at the image +wait(5000) diff --git a/examples/ev3/screen_print/.gitignore b/examples/ev3/screen_print/.gitignore new file mode 100644 index 0000000..00f2d38 --- /dev/null +++ b/examples/ev3/screen_print/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.venv/ diff --git a/examples/ev3/screen_print/.vscode/extensions.json b/examples/ev3/screen_print/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/screen_print/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/screen_print/.vscode/launch.json b/examples/ev3/screen_print/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/screen_print/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/screen_print/.vscode/settings.json b/examples/ev3/screen_print/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/screen_print/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/screen_print/main.py b/examples/ev3/screen_print/main.py new file mode 100644 index 0000000..1e12bdd --- /dev/null +++ b/examples/ev3/screen_print/main.py @@ -0,0 +1,34 @@ +#!/usr/bin/env pybricks-micropython + +from pybricks.hubs import EV3Brick +from pybricks.tools import wait +from pybricks.media.ev3dev import Font + +# It takes some time for fonts to load from file, so it is best to only +# load them once at the beginning of the program like this: +tiny_font = Font(size=6) +big_font = Font(size=24, bold=True) +chinese_font = Font(size=24, lang='zh-cn') + + +# Initialize the EV3 +ev3 = EV3Brick() + + +# Say hello +ev3.screen.print('Hello!') + +# Say tiny hello +ev3.screen.set_font(tiny_font) +ev3.screen.print('hello') + +# Say big hello +ev3.screen.set_font(big_font) +ev3.screen.print('HELLO') + +# Say Chinese hello +ev3.screen.set_font(chinese_font) +ev3.screen.print('你好') + +# Wait some time to look at the screen +wait(5000) diff --git a/examples/ev3/speaker_basics/.gitignore b/examples/ev3/speaker_basics/.gitignore new file mode 100644 index 0000000..00f2d38 --- /dev/null +++ b/examples/ev3/speaker_basics/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.venv/ diff --git a/examples/ev3/speaker_basics/.vscode/extensions.json b/examples/ev3/speaker_basics/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/speaker_basics/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/speaker_basics/.vscode/launch.json b/examples/ev3/speaker_basics/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/speaker_basics/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/speaker_basics/.vscode/settings.json b/examples/ev3/speaker_basics/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/speaker_basics/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/speaker_basics/main.py b/examples/ev3/speaker_basics/main.py new file mode 100644 index 0000000..bc7a3b5 --- /dev/null +++ b/examples/ev3/speaker_basics/main.py @@ -0,0 +1,55 @@ +#!/usr/bin/env pybricks-micropython + +from pybricks.hubs import EV3Brick +from pybricks.tools import wait +from pybricks.media.ev3dev import SoundFile + + +# Initialize the EV3 +ev3 = EV3Brick() + + +# BEEP ######################################################################## + +# Simple beep +ev3.speaker.beep() + +wait(1000) + +# Interesting beeps +for f in range(100, 500, 100): + ev3.speaker.beep(f) + +wait(1000) + + +# PLAY NOTES ################################################################## + +# Twinkle, Twinkle Little Star +A = ['C4/4', 'C4/4', 'G4/4', 'G4/4', 'A4/4', 'A4/4', 'G4/2', + 'F4/4', 'F4/4', 'E4/4', 'E4/4', 'D4/4', 'D4/4', 'C4/2'] +B = ['G4/4', 'G4/4', 'F4/4', 'F4/4', 'E4/4', 'E4/4', 'D4/2'] * 2 +TWINKLE = A + B + A + +ev3.speaker.play_notes(TWINKLE) + +wait(1000) + + +# PLAY FILE ################################################################### + +ev3.speaker.play_file(SoundFile.HELLO) + +wait(1000) + + +# TEXT TO SPEECH ############################################################## + +# Say something in English +ev3.speaker.say('I am am E V 3. Pleased to meet you.') + +# Say something in Danish + female +ev3.speaker.set_speech_options(voice='da+f5') +ev3.speaker.say('Leg godt!') + +wait(1000) diff --git a/examples/ev3/uart_basics/.gitignore b/examples/ev3/uart_basics/.gitignore new file mode 100644 index 0000000..9b5f630 --- /dev/null +++ b/examples/ev3/uart_basics/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +venv/ diff --git a/examples/ev3/uart_basics/.vscode/extensions.json b/examples/ev3/uart_basics/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/uart_basics/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/uart_basics/.vscode/launch.json b/examples/ev3/uart_basics/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/uart_basics/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/uart_basics/.vscode/settings.json b/examples/ev3/uart_basics/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/uart_basics/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/uart_basics/main.py b/examples/ev3/uart_basics/main.py new file mode 100644 index 0000000..b7fedf9 --- /dev/null +++ b/examples/ev3/uart_basics/main.py @@ -0,0 +1,25 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.hubs import EV3Brick +from pybricks.iodevices import UARTDevice +from pybricks.parameters import Port +from pybricks.media.ev3dev import SoundFile + +# Initialize the EV3 +ev3 = EV3Brick() + +# Initialize sensor port 2 as a uart device +ser = UARTDevice(Port.S2, baudrate=115200) + +# Write some data +ser.write(b'\r\nHello, world!\r\n') + +# Play a sound while we wait for some data +for i in range(3): + ev3.speaker.play_file(SoundFile.HELLO) + ev3.speaker.play_file(SoundFile.GOOD) + ev3.speaker.play_file(SoundFile.MORNING) + print("Bytes waiting to be read:", ser.waiting()) + +# Read all data received while the sound was playing +data = ser.read_all() +print(data) diff --git a/examples/ev3/vernier_surface_temperature/.gitignore b/examples/ev3/vernier_surface_temperature/.gitignore new file mode 100644 index 0000000..9b5f630 --- /dev/null +++ b/examples/ev3/vernier_surface_temperature/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +venv/ diff --git a/examples/ev3/vernier_surface_temperature/.vscode/extensions.json b/examples/ev3/vernier_surface_temperature/.vscode/extensions.json new file mode 100644 index 0000000..f8f1a44 --- /dev/null +++ b/examples/ev3/vernier_surface_temperature/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/examples/ev3/vernier_surface_temperature/.vscode/launch.json b/examples/ev3/vernier_surface_temperature/.vscode/launch.json new file mode 100644 index 0000000..af12883 --- /dev/null +++ b/examples/ev3/vernier_surface_temperature/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/examples/ev3/vernier_surface_temperature/.vscode/settings.json b/examples/ev3/vernier_surface_temperature/.vscode/settings.json new file mode 100644 index 0000000..37c9a5d --- /dev/null +++ b/examples/ev3/vernier_surface_temperature/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/examples/ev3/vernier_surface_temperature/main.py b/examples/ev3/vernier_surface_temperature/main.py new file mode 100644 index 0000000..4045ff5 --- /dev/null +++ b/examples/ev3/vernier_surface_temperature/main.py @@ -0,0 +1,32 @@ +#!/usr/bin/env pybricks-micropython +from pybricks.parameters import Port +from pybricks.nxtdevices import VernierAdapter + +from math import log + + +# Conversion formula for Surface Temperature Sensor +def convert_raw_to_temperature(voltage): + + # Convert the raw voltage to the NTC resistance + # according to the Vernier Adapter EV3 block. + counts = voltage/5000*4096 + ntc = 15000*(counts)/(4130-counts) + + # Handle log(0) safely: make sure that ntc value is positive. + if ntc <= 0: + ntc = 1 + + # Apply Steinhart-Hart equation as given in the sensor documentation. + K0 = 1.02119e-3 + K1 = 2.22468e-4 + K2 = 1.33342e-7 + return 1/(K0 + K1*log(ntc) + K2*log(ntc)**3) + + +# Initialize the adapter on port 1 +thermometer = VernierAdapter(Port.S1, convert_raw_to_temperature) + +# Get the measured value and print it +temp = thermometer.value() +print(temp) diff --git a/examples/pup/hub_cityhub/light_animate.py b/examples/pup/hub_cityhub/light_animate.py new file mode 100644 index 0000000..db71543 --- /dev/null +++ b/examples/pup/hub_cityhub/light_animate.py @@ -0,0 +1,23 @@ +from pybricks.hubs import CityHub +from pybricks.parameters import Color +from pybricks.tools import wait +from math import sin, pi + +# Initialize the hub. +hub = CityHub() + +# Make an animation with multiple colors. +hub.light.animate([Color.RED, Color.GREEN, None], interval=500) + +wait(10000) + +# Make the color RED grow faint and bright using a sine pattern. +hub.light.animate( + [Color.RED * (0.5 * sin(i / 15 * pi) + 0.5) for i in range(30)], 40) + +wait(10000) + +# Cycle through a rainbow of colors. +hub.light.animate([Color(h=i*8) for i in range(45)], interval=40) + +wait(10000) diff --git a/examples/pup/hub_cityhub/light_blink.py b/examples/pup/hub_cityhub/light_blink.py new file mode 100644 index 0000000..e245665 --- /dev/null +++ b/examples/pup/hub_cityhub/light_blink.py @@ -0,0 +1,16 @@ +from pybricks.hubs import CityHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub +hub = CityHub() + +# Keep blinking red on and off. +hub.light.blink(Color.RED, [500, 500]) + +wait(10000) + +# Keep blinking green slowly and then quickly. +hub.light.blink(Color.GREEN, [500, 500, 50, 900]) + +wait(10000) diff --git a/examples/pup/hub_cityhub/light_hsv.py b/examples/pup/hub_cityhub/light_hsv.py new file mode 100644 index 0000000..38d43ed --- /dev/null +++ b/examples/pup/hub_cityhub/light_hsv.py @@ -0,0 +1,21 @@ +from pybricks.hubs import CityHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = CityHub() + +# Show the color at 30% brightness. +hub.light.on(Color.RED * 0.3) + +wait(2000) + +# Use your own custom color. +hub.light.on(Color(h=30, s=100, v=50)) + +wait(2000) + +# Go through all the colors. +for hue in range(360): + hub.light.on(Color(hue)) + wait(10) diff --git a/examples/pup/hub_cityhub/light_off.py b/examples/pup/hub_cityhub/light_off.py new file mode 100644 index 0000000..2ca8f20 --- /dev/null +++ b/examples/pup/hub_cityhub/light_off.py @@ -0,0 +1,15 @@ +from pybricks.hubs import CityHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = CityHub() + +# Turn the light on and off 5 times. +for i in range(5): + + hub.light.on(Color.RED) + wait(1000) + + hub.light.off() + wait(500) diff --git a/examples/pup/hub_inventorhub/light_animate.py b/examples/pup/hub_inventorhub/light_animate.py new file mode 100644 index 0000000..e8d7da9 --- /dev/null +++ b/examples/pup/hub_inventorhub/light_animate.py @@ -0,0 +1,23 @@ +from pybricks.hubs import InventorHub +from pybricks.parameters import Color +from pybricks.tools import wait +from math import sin, pi + +# Initialize the hub. +hub = InventorHub() + +# Make an animation with multiple colors. +hub.light.animate([Color.RED, Color.GREEN, None], interval=500) + +wait(10000) + +# Make the color RED grow faint and bright using a sine pattern. +hub.light.animate( + [Color.RED * (0.5 * sin(i / 15 * pi) + 0.5) for i in range(30)], 40) + +wait(10000) + +# Cycle through a rainbow of colors. +hub.light.animate([Color(h=i*8) for i in range(45)], interval=40) + +wait(10000) diff --git a/examples/pup/hub_inventorhub/light_blink.py b/examples/pup/hub_inventorhub/light_blink.py new file mode 100644 index 0000000..d94c94b --- /dev/null +++ b/examples/pup/hub_inventorhub/light_blink.py @@ -0,0 +1,16 @@ +from pybricks.hubs import InventorHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub +hub = InventorHub() + +# Keep blinking red on and off. +hub.light.blink(Color.RED, [500, 500]) + +wait(10000) + +# Keep blinking green slowly and then quickly. +hub.light.blink(Color.GREEN, [500, 500, 50, 900]) + +wait(10000) diff --git a/examples/pup/hub_inventorhub/light_hsv.py b/examples/pup/hub_inventorhub/light_hsv.py new file mode 100644 index 0000000..4420239 --- /dev/null +++ b/examples/pup/hub_inventorhub/light_hsv.py @@ -0,0 +1,21 @@ +from pybricks.hubs import InventorHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = InventorHub() + +# Show the color at 30% brightness. +hub.light.on(Color.RED * 0.3) + +wait(2000) + +# Use your own custom color. +hub.light.on(Color(h=30, s=100, v=50)) + +wait(2000) + +# Go through all the colors. +for hue in range(360): + hub.light.on(Color(hue)) + wait(10) diff --git a/examples/pup/hub_inventorhub/light_off.py b/examples/pup/hub_inventorhub/light_off.py new file mode 100644 index 0000000..1a23440 --- /dev/null +++ b/examples/pup/hub_inventorhub/light_off.py @@ -0,0 +1,15 @@ +from pybricks.hubs import InventorHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = InventorHub() + +# Turn the light on and off 5 times. +for i in range(5): + + hub.light.on(Color.RED) + wait(1000) + + hub.light.off() + wait(500) diff --git a/examples/pup/hub_movehub/light_animate.py b/examples/pup/hub_movehub/light_animate.py new file mode 100644 index 0000000..4de1486 --- /dev/null +++ b/examples/pup/hub_movehub/light_animate.py @@ -0,0 +1,16 @@ +from pybricks.hubs import MoveHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = MoveHub() + +# Make an animation with multiple colors. +hub.light.animate([Color.RED, Color.GREEN, None], interval=500) + +wait(10000) + +# Cycle through a rainbow of colors. +hub.light.animate([Color(h=i*8) for i in range(45)], interval=40) + +wait(10000) diff --git a/examples/pup/hub_movehub/light_blink.py b/examples/pup/hub_movehub/light_blink.py new file mode 100644 index 0000000..0e31f46 --- /dev/null +++ b/examples/pup/hub_movehub/light_blink.py @@ -0,0 +1,16 @@ +from pybricks.hubs import MoveHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub +hub = MoveHub() + +# Keep blinking red on and off. +hub.light.blink(Color.RED, [500, 500]) + +wait(10000) + +# Keep blinking green slowly and then quickly. +hub.light.blink(Color.GREEN, [500, 500, 50, 900]) + +wait(10000) diff --git a/examples/pup/hub_movehub/light_hsv.py b/examples/pup/hub_movehub/light_hsv.py new file mode 100644 index 0000000..50b8522 --- /dev/null +++ b/examples/pup/hub_movehub/light_hsv.py @@ -0,0 +1,16 @@ +from pybricks.hubs import MoveHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = MoveHub() + +# Use your own custom color. +hub.light.on(Color(h=30, s=100, v=50)) + +wait(2000) + +# Go through all the colors. +for hue in range(360): + hub.light.on(Color(hue)) + wait(10) diff --git a/examples/pup/hub_movehub/light_off.py b/examples/pup/hub_movehub/light_off.py new file mode 100644 index 0000000..5de6a43 --- /dev/null +++ b/examples/pup/hub_movehub/light_off.py @@ -0,0 +1,15 @@ +from pybricks.hubs import MoveHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = MoveHub() + +# Turn the light on and off 5 times. +for i in range(5): + + hub.light.on(Color.RED) + wait(1000) + + hub.light.off() + wait(500) diff --git a/examples/pup/hub_primehub/light_animate.py b/examples/pup/hub_primehub/light_animate.py new file mode 100644 index 0000000..1080154 --- /dev/null +++ b/examples/pup/hub_primehub/light_animate.py @@ -0,0 +1,23 @@ +from pybricks.hubs import PrimeHub +from pybricks.parameters import Color +from pybricks.tools import wait +from math import sin, pi + +# Initialize the hub. +hub = PrimeHub() + +# Make an animation with multiple colors. +hub.light.animate([Color.RED, Color.GREEN, None], interval=500) + +wait(10000) + +# Make the color RED grow faint and bright using a sine pattern. +hub.light.animate( + [Color.RED * (0.5 * sin(i / 15 * pi) + 0.5) for i in range(30)], 40) + +wait(10000) + +# Cycle through a rainbow of colors. +hub.light.animate([Color(h=i*8) for i in range(45)], interval=40) + +wait(10000) diff --git a/examples/pup/hub_primehub/light_blink.py b/examples/pup/hub_primehub/light_blink.py new file mode 100644 index 0000000..1df0347 --- /dev/null +++ b/examples/pup/hub_primehub/light_blink.py @@ -0,0 +1,16 @@ +from pybricks.hubs import PrimeHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub +hub = PrimeHub() + +# Keep blinking red on and off. +hub.light.blink(Color.RED, [500, 500]) + +wait(10000) + +# Keep blinking green slowly and then quickly. +hub.light.blink(Color.GREEN, [500, 500, 50, 900]) + +wait(10000) diff --git a/examples/pup/hub_primehub/light_hsv.py b/examples/pup/hub_primehub/light_hsv.py new file mode 100644 index 0000000..7812ec5 --- /dev/null +++ b/examples/pup/hub_primehub/light_hsv.py @@ -0,0 +1,21 @@ +from pybricks.hubs import PrimeHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = PrimeHub() + +# Show the color at 30% brightness. +hub.light.on(Color.RED * 0.3) + +wait(2000) + +# Use your own custom color. +hub.light.on(Color(h=30, s=100, v=50)) + +wait(2000) + +# Go through all the colors. +for hue in range(360): + hub.light.on(Color(hue)) + wait(10) diff --git a/examples/pup/hub_primehub/light_off.py b/examples/pup/hub_primehub/light_off.py new file mode 100644 index 0000000..f13eb0d --- /dev/null +++ b/examples/pup/hub_primehub/light_off.py @@ -0,0 +1,15 @@ +from pybricks.hubs import PrimeHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = PrimeHub() + +# Turn the light on and off 5 times. +for i in range(5): + + hub.light.on(Color.RED) + wait(1000) + + hub.light.off() + wait(500) diff --git a/examples/pup/hub_shared/light_animate.py b/examples/pup/hub_shared/light_animate.py new file mode 100644 index 0000000..f6426be --- /dev/null +++ b/examples/pup/hub_shared/light_animate.py @@ -0,0 +1,25 @@ +from pybricks.hubs import ExampleHub +from pybricks.parameters import Color +from pybricks.tools import wait +# MOVEHUB SKIP_NEXT 1 +from math import sin, pi + +# Initialize the hub. +hub = ExampleHub() + +# Make an animation with multiple colors. +hub.light.animate([Color.RED, Color.GREEN, None], interval=500) + +wait(10000) + +# MOVEHUB SKIP_NEXT 6 +# Make the color RED grow faint and bright using a sine pattern. +hub.light.animate( + [Color.RED * (0.5 * sin(i / 15 * pi) + 0.5) for i in range(30)], 40) + +wait(10000) + +# Cycle through a rainbow of colors. +hub.light.animate([Color(h=i*8) for i in range(45)], interval=40) + +wait(10000) diff --git a/examples/pup/hub_shared/light_blink.py b/examples/pup/hub_shared/light_blink.py new file mode 100644 index 0000000..5773a76 --- /dev/null +++ b/examples/pup/hub_shared/light_blink.py @@ -0,0 +1,16 @@ +from pybricks.hubs import ExampleHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub +hub = ExampleHub() + +# Keep blinking red on and off. +hub.light.blink(Color.RED, [500, 500]) + +wait(10000) + +# Keep blinking green slowly and then quickly. +hub.light.blink(Color.GREEN, [500, 500, 50, 900]) + +wait(10000) diff --git a/examples/pup/hub_shared/light_hsv.py b/examples/pup/hub_shared/light_hsv.py new file mode 100644 index 0000000..158d7ae --- /dev/null +++ b/examples/pup/hub_shared/light_hsv.py @@ -0,0 +1,22 @@ +from pybricks.hubs import ExampleHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = ExampleHub() + +# MOVEHUB SKIP_NEXT 5 +# Show the color at 30% brightness. +hub.light.on(Color.RED * 0.3) + +wait(2000) + +# Use your own custom color. +hub.light.on(Color(h=30, s=100, v=50)) + +wait(2000) + +# Go through all the colors. +for hue in range(360): + hub.light.on(Color(hue)) + wait(10) diff --git a/examples/pup/hub_shared/light_off.py b/examples/pup/hub_shared/light_off.py new file mode 100644 index 0000000..2d47358 --- /dev/null +++ b/examples/pup/hub_shared/light_off.py @@ -0,0 +1,15 @@ +from pybricks.hubs import ExampleHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = ExampleHub() + +# Turn the light on and off 5 times. +for i in range(5): + + hub.light.on(Color.RED) + wait(1000) + + hub.light.off() + wait(500) diff --git a/examples/pup/hub_shared/make_shared_examples.py b/examples/pup/hub_shared/make_shared_examples.py new file mode 100644 index 0000000..42980d6 --- /dev/null +++ b/examples/pup/hub_shared/make_shared_examples.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"""Replaces all instances of ExampleHub in template with actual hub names. + +Optionally skips examples that do not work on a platform. +""" +import os + +# Which instance to replace +EXAMPLE_HUB = 'ExampleHub' + +# Define which hubs to run +HUBS = ['MoveHub', 'CityHub', 'TechnicHub', 'PrimeHub', 'InventorHub'] + +# This flag indicates to skip next X lines in a script +SKIP_FLAG = 'SKIP_NEXT' +skip_remaining = 0 + +# Get list of scripts to be parsed +script_names = [f for f in os.listdir('.') if f != 'make_shared_examples.py'] + +for hub in HUBS: + # Determine path to the hub + hub_path = os.path.join('..', 'hub_' + hub.lower()) + os.makedirs(hub_path, exist_ok=True) + + # Go through all template scripts + for script in (open(f, 'r') for f in script_names): + + # Open destination script: + with open(os.path.join(hub_path, script.name), 'w') as dest_file: + + # Read script line by line + for line in script.readlines(): + + # Replace hub name if present + line = line.replace(EXAMPLE_HUB, hub) + + # If there is a skip flag, parse it + if skip_remaining == 0 and SKIP_FLAG in line: + idx = line.find(SKIP_FLAG) + + # Get hub name and how many lines to skip + _, skip_hub, _, skip_len = line.split() + + # Skip lines if needed, and always skip the flag itself + if hub.lower() == skip_hub.lower(): + skip_remaining = int(skip_len) + 1 + else: + skip_remaining = 1 + + # If there are some lines left to skip, do so + if skip_remaining > 0: + skip_remaining -= 1 + # Otherwise print the line + else: + dest_file.writelines(line) diff --git a/examples/pup/hub_technichub/light_animate.py b/examples/pup/hub_technichub/light_animate.py new file mode 100644 index 0000000..06f68ab --- /dev/null +++ b/examples/pup/hub_technichub/light_animate.py @@ -0,0 +1,23 @@ +from pybricks.hubs import TechnicHub +from pybricks.parameters import Color +from pybricks.tools import wait +from math import sin, pi + +# Initialize the hub. +hub = TechnicHub() + +# Make an animation with multiple colors. +hub.light.animate([Color.RED, Color.GREEN, None], interval=500) + +wait(10000) + +# Make the color RED grow faint and bright using a sine pattern. +hub.light.animate( + [Color.RED * (0.5 * sin(i / 15 * pi) + 0.5) for i in range(30)], 40) + +wait(10000) + +# Cycle through a rainbow of colors. +hub.light.animate([Color(h=i*8) for i in range(45)], interval=40) + +wait(10000) diff --git a/examples/pup/hub_technichub/light_blink.py b/examples/pup/hub_technichub/light_blink.py new file mode 100644 index 0000000..441ad62 --- /dev/null +++ b/examples/pup/hub_technichub/light_blink.py @@ -0,0 +1,16 @@ +from pybricks.hubs import TechnicHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub +hub = TechnicHub() + +# Keep blinking red on and off. +hub.light.blink(Color.RED, [500, 500]) + +wait(10000) + +# Keep blinking green slowly and then quickly. +hub.light.blink(Color.GREEN, [500, 500, 50, 900]) + +wait(10000) diff --git a/examples/pup/hub_technichub/light_hsv.py b/examples/pup/hub_technichub/light_hsv.py new file mode 100644 index 0000000..ae76cf5 --- /dev/null +++ b/examples/pup/hub_technichub/light_hsv.py @@ -0,0 +1,21 @@ +from pybricks.hubs import TechnicHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = TechnicHub() + +# Show the color at 30% brightness. +hub.light.on(Color.RED * 0.3) + +wait(2000) + +# Use your own custom color. +hub.light.on(Color(h=30, s=100, v=50)) + +wait(2000) + +# Go through all the colors. +for hue in range(360): + hub.light.on(Color(hue)) + wait(10) diff --git a/examples/pup/hub_technichub/light_off.py b/examples/pup/hub_technichub/light_off.py new file mode 100644 index 0000000..4227d2f --- /dev/null +++ b/examples/pup/hub_technichub/light_off.py @@ -0,0 +1,15 @@ +from pybricks.hubs import TechnicHub +from pybricks.parameters import Color +from pybricks.tools import wait + +# Initialize the hub. +hub = TechnicHub() + +# Turn the light on and off 5 times. +for i in range(5): + + hub.light.on(Color.RED) + wait(1000) + + hub.light.off() + wait(500) diff --git a/examples/pup/light/basics.py b/examples/pup/light/basics.py new file mode 100644 index 0000000..a659757 --- /dev/null +++ b/examples/pup/light/basics.py @@ -0,0 +1,16 @@ +from pybricks.pupdevices import Light +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the light. +light = Light(Port.A) + +# Blink the light forever. +while True: + # Turn the light on at 100% brightness. + light.on(100) + wait(500) + + # Turn the light off. + light.off() + wait(500) diff --git a/examples/pup/light/math.py b/examples/pup/light/math.py new file mode 100644 index 0000000..459d32e --- /dev/null +++ b/examples/pup/light/math.py @@ -0,0 +1,27 @@ +from pybricks.pupdevices import Light +from pybricks.parameters import Port +from pybricks.tools import wait, StopWatch + +# The math module is part of standard MicroPython: +# https://docs.micropython.org/en/latest/library/math.html +from math import pi, cos + +# Initialize the light and a StopWatch. +light = Light(Port.A) +watch = StopWatch() + +# Cosine pattern properties. +PERIOD = 2000 +MAX = 100 + +# Make the brightness fade in and out. +while True: + # Get phase of the cosine. + phase = watch.time()/PERIOD*2*pi + + # Evaluate the brightness. + brightness = (0.5 - 0.5*cos(phase))*MAX + + # Set light brightness and wait a bit. + light.on(brightness) + wait(10) diff --git a/examples/pup/motor/motor_action_basic.py b/examples/pup/motor/motor_action_basic.py new file mode 100644 index 0000000..a7dbdb6 --- /dev/null +++ b/examples/pup/motor/motor_action_basic.py @@ -0,0 +1,46 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize a motor on port A. +example_motor = Motor(Port.A) + +# Run at 500 deg/s and then stop by coasting. +print("Demo of run") +example_motor.run(500) +wait(1500) +example_motor.stop() +wait(1500) + +# Run at 70% duty cycle ("power") and then stop by coasting. +print("Demo of dc") +example_motor.dc(50) +wait(1500) +example_motor.stop() +wait(1500) + +# Run at 500 deg/s for two seconds. +print("Demo of run_time") +example_motor.run_time(500, 2000) +wait(1500) + +# Run at 500 deg/s for 90 degrees. +print("Demo of run_angle") +example_motor.run_angle(500, 180) +wait(1500) + +# Run at 500 deg/s back to the 0 angle +print("Demo of run_target to 0") +example_motor.run_target(500, 0) +wait(1500) + +# Run at 500 deg/s back to the -90 angle +print("Demo of run_target to -90") +example_motor.run_target(500, -90) +wait(1500) + +# Run at 500 deg/s until the motor stalls +print("Demo of run_until_stalled") +example_motor.run_until_stalled(500) +print("Done") +wait(1500) diff --git a/examples/pup/motor/motor_action_then.py b/examples/pup/motor/motor_action_then.py new file mode 100644 index 0000000..bb06b14 --- /dev/null +++ b/examples/pup/motor/motor_action_then.py @@ -0,0 +1,24 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port, Stop +from pybricks.tools import wait + +# Initialize a motor on port A. +example_motor = Motor(Port.A) + +# By default, the motor holds the position. It keeps +# correcting the angle if you move it. +example_motor.run_angle(500, 360) +wait(1000) + +# This does exactly the same as above. +example_motor.run_angle(500, 360, then=Stop.HOLD) +wait(1000) + +# You can also brake. This applies some resistance +# but the motor does not move back if you move it. +example_motor.run_angle(500, 360, then=Stop.BRAKE) +wait(1000) + +# This makes the motor coast freely after it stops. +example_motor.run_angle(500, 360, then=Stop.COAST) +wait(1000) diff --git a/examples/pup/motor/motor_action_wait.py b/examples/pup/motor/motor_action_wait.py new file mode 100644 index 0000000..6f26500 --- /dev/null +++ b/examples/pup/motor/motor_action_wait.py @@ -0,0 +1,14 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port + +# Initialize motors on port A and B. +track_motor = Motor(Port.A) +gripper_motor = Motor(Port.B) + +# Make the track motor start moving, +# but don't wait for it to finish. +track_motor.run_angle(500, 360, wait=False) + +# Now make the gripper motor rotate. This +# means they move at the same time. +gripper_motor.run_angle(200, 720) diff --git a/examples/pup/motor/motor_action_wait_advanced.py b/examples/pup/motor/motor_action_wait_advanced.py new file mode 100644 index 0000000..a2b1e05 --- /dev/null +++ b/examples/pup/motor/motor_action_wait_advanced.py @@ -0,0 +1,18 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize motors on port A and B. +track_motor = Motor(Port.A) +gripper_motor = Motor(Port.B) + +# Make both motors perform an action with wait=False +track_motor.run_angle(500, 360, wait=False) +gripper_motor.run_angle(200, 720, wait=False) + +# While one or both of the motors are not done yet, +# do something else. In this example, just wait. +while not track_motor.control.done() or not gripper_motor.control.done(): + wait(10) + +print("Both motors are done!") diff --git a/examples/pup/motor/motor_init_basic.py b/examples/pup/motor/motor_init_basic.py new file mode 100644 index 0000000..c771045 --- /dev/null +++ b/examples/pup/motor/motor_init_basic.py @@ -0,0 +1,18 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize a motor on port A. +example_motor = Motor(Port.A) + +# Make the motor run clockwise at 500 degrees per second. +example_motor.run(500) + +# Wait for three seconds. +wait(3000) + +# Make the motor run counterclockwise at 500 degrees per second. +example_motor.run(-500) + +# Wait for three seconds. +wait(3000) diff --git a/examples/pup/motor/motor_init_direction.py b/examples/pup/motor/motor_init_direction.py new file mode 100644 index 0000000..a26f5f4 --- /dev/null +++ b/examples/pup/motor/motor_init_direction.py @@ -0,0 +1,16 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port, Direction +from pybricks.tools import wait + +# Initialize a motor on port A with the positive direction as counterclockwise. +example_motor = Motor(Port.A, Direction.COUNTERCLOCKWISE) + +# When we choose a positive speed value, the motor now goes counterclockwise. +example_motor.run(500) + +# This is useful when your motor is mounted in reverse or upside down. +# By changing the positive direction, your script will be easier to read, +# because a positive value now makes your robot/mechanism go forward. + +# Wait for three seconds. +wait(3000) diff --git a/examples/pup/motor/motor_init_gears.py b/examples/pup/motor/motor_init_gears.py new file mode 100644 index 0000000..59086ca --- /dev/null +++ b/examples/pup/motor/motor_init_gears.py @@ -0,0 +1,15 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port, Direction +from pybricks.tools import wait + +# Initialize a motor on port A with the positive direction as counterclockwise. +# Also specify one gear train with a 12-tooth and a 36-tooth gear. The 12-tooth +# gear is attached to the motor axle. The 36-tooth gear is at the output axle. +geared_motor = Motor(Port.A, Direction.COUNTERCLOCKWISE, [12, 36]) + +# Make the output axle run at 100 degrees per second. The motor speed +# is automatically increased to compensate for the gears. +geared_motor.run(100) + +# Wait for three seconds. +wait(3000) diff --git a/examples/pup/motor/motor_init_multiple.py b/examples/pup/motor/motor_init_multiple.py new file mode 100644 index 0000000..c93379c --- /dev/null +++ b/examples/pup/motor/motor_init_multiple.py @@ -0,0 +1,14 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize motors on port A and B. +track_motor = Motor(Port.A) +gripper_motor = Motor(Port.B) + +# Make both motors run at 500 degrees per second. +track_motor.run(500) +gripper_motor.run(500) + +# Wait for three seconds. +wait(3000) diff --git a/examples/pup/motor/motor_measure.py b/examples/pup/motor/motor_measure.py new file mode 100644 index 0000000..e00974a --- /dev/null +++ b/examples/pup/motor/motor_measure.py @@ -0,0 +1,22 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize a motor on port A. +example_motor = Motor(Port.A) + +# Start moving at 300 degrees per second. +example_motor.run(300) + +# Display the angle and speed 50 times. +for i in range(100): + + # Read the angle (degrees) and speed (degrees per second). + angle = example_motor.angle() + speed = example_motor.speed() + + # Print the values. + print(angle, speed) + + # Wait some time so we can read what is displayed. + wait(200) diff --git a/examples/pup/motor/motor_reset_angle.py b/examples/pup/motor/motor_reset_angle.py new file mode 100644 index 0000000..ccd8b8e --- /dev/null +++ b/examples/pup/motor/motor_reset_angle.py @@ -0,0 +1,17 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port + +# Initialize a motor on port A. +example_motor = Motor(Port.A) + +# Reset the angle to 0. +example_motor.reset_angle(0) + +# Reset the angle to 1234. +example_motor.reset_angle(1234) + +# Reset the angle to the absolute angle. +# This is only supported on motors that have +# an absolute encoder. For other motors, this +# will raise an error. +example_motor.reset_angle() diff --git a/examples/pup/motor/motor_stop.py b/examples/pup/motor/motor_stop.py new file mode 100644 index 0000000..a65d0ac --- /dev/null +++ b/examples/pup/motor/motor_stop.py @@ -0,0 +1,30 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize a motor on port A. +example_motor = Motor(Port.A) + +# Run at 500 deg/s and then stop by coasting. +example_motor.run(500) +wait(1500) +example_motor.stop() +wait(1500) + +# Run at 500 deg/s and then stop by braking. +example_motor.run(500) +wait(1500) +example_motor.brake() +wait(1500) + +# Run at 500 deg/s and then stop by holding. +example_motor.run(500) +wait(1500) +example_motor.hold() +wait(1500) + +# Run at 500 deg/s and then stop by running at 0 speed. +example_motor.run(500) +wait(1500) +example_motor.run(0) +wait(1500) diff --git a/examples/pup/motor/motor_until_stalled.py b/examples/pup/motor/motor_until_stalled.py new file mode 100644 index 0000000..e39b619 --- /dev/null +++ b/examples/pup/motor/motor_until_stalled.py @@ -0,0 +1,26 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port + +# Initialize a motor on port A. +example_motor = Motor(Port.A) + +# We'll use a speed of 200 deg/s in all our commands. +speed = 200 + +# Run the motor in reverse until it hits a mechanical stop. +# The duty_limit=30 setting means that it will apply only 30% +# of the maximum torque against the mechanical stop. This way, +# you don't push against it with too much force. +example_motor.run_until_stalled(-speed, duty_limit=30) + +# Reset the angle to 0. Now whenever the angle is 0, you know +# that it has reached the mechanical endpoint. +example_motor.reset_angle(0) + +# Now make the motor go back and forth in a loop. +# This will now work the same regardless of the +# initial motor angle, because we always start +# from the mechanical endpoint. +for count in range(10): + example_motor.run_target(speed, 180) + example_motor.run_target(speed, 90) diff --git a/examples/pup/motor/motor_until_stalled_center.py b/examples/pup/motor/motor_until_stalled_center.py new file mode 100644 index 0000000..907b10c --- /dev/null +++ b/examples/pup/motor/motor_until_stalled_center.py @@ -0,0 +1,24 @@ +from pybricks.pupdevices import Motor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize a motor on port A. +example_motor = Motor(Port.A) + +# Please have a look at the previous example first. This example +# finds two endspoints and then makes the middle the zero point. + +# The run_until_stalled gives us the angle at which it stalled. +# We want to know this value for both endpoints. +left_end = example_motor.run_until_stalled(-200, duty_limit=30) +right_end = example_motor.run_until_stalled(200, duty_limit=30) + +# We have just moved to the rightmost endstop. So, we can reset +# this angle to be half the distance between the two endpoints. +# That way, the middle corresponds to 0 degrees. +example_motor.reset_angle((right_end - left_end) / 2) + +# From now on we can simply run towards zero to reach the middle. +example_motor.run_target(200, 0) + +wait(1000) diff --git a/examples/pup/motor_dc/motor_dc_init_basic.py b/examples/pup/motor_dc/motor_dc_init_basic.py new file mode 100644 index 0000000..693ea54 --- /dev/null +++ b/examples/pup/motor_dc/motor_dc_init_basic.py @@ -0,0 +1,18 @@ +from pybricks.pupdevices import DCMotor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize a motor without rotation sensors on port A. +example_motor = DCMotor(Port.A) + +# Make the motor go clockwise (forward) at 70% duty cycle ("70% power"). +example_motor.dc(70) + +# Wait for three seconds. +wait(3000) + +# Make the motor go counterclockwise (backward) at 70% duty cycle. +example_motor.dc(-70) + +# Wait for three seconds. +wait(3000) diff --git a/examples/pup/motor_dc/motor_dc_init_direction.py b/examples/pup/motor_dc/motor_dc_init_direction.py new file mode 100644 index 0000000..046d0d7 --- /dev/null +++ b/examples/pup/motor_dc/motor_dc_init_direction.py @@ -0,0 +1,17 @@ +from pybricks.pupdevices import DCMotor +from pybricks.parameters import Port, Direction +from pybricks.tools import wait + +# Initialize a motor without rotation sensors on port A, +# with the positive direction as counterclockwise. +example_motor = DCMotor(Port.A, Direction.COUNTERCLOCKWISE) + +# When we choose a positive duty cycle, the motor now goes counterclockwise. +example_motor.dc(70) + +# This is useful when your (train) motor is mounted in reverse or upside down. +# By changing the positive direction, your script will be easier to read, +# because a positive value now makes your train/robot go forward. + +# Wait for three seconds. +wait(3000) diff --git a/examples/pup/motor_dc/motor_dc_stop.py b/examples/pup/motor_dc/motor_dc_stop.py new file mode 100644 index 0000000..a73aa31 --- /dev/null +++ b/examples/pup/motor_dc/motor_dc_stop.py @@ -0,0 +1,16 @@ +from pybricks.pupdevices import DCMotor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize a motor without rotation sensors on port A. +example_motor = DCMotor(Port.A) + +# Start and stop 10 times. +for count in range(10): + print("Counter:", count) + + example_motor.dc(70) + wait(1000) + + example_motor.stop() + wait(1000) diff --git a/examples/pup/motor_pf/motor_pf_basics.py b/examples/pup/motor_pf/motor_pf_basics.py new file mode 100644 index 0000000..25558d3 --- /dev/null +++ b/examples/pup/motor_pf/motor_pf_basics.py @@ -0,0 +1,20 @@ +from pybricks.pupdevices import ColorDistanceSensor, PFMotor +from pybricks.parameters import Port, Color +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorDistanceSensor(Port.B) + +# Initialize a motor on channel 1, on the red output. +motor = PFMotor(sensor, 1, Color.RED) + +# Rotate and then stop. +motor.dc(100) +wait(1000) +motor.stop() +wait(1000) + +# Rotate the other way at half speed, and then stop. +motor.dc(-50) +wait(1000) +motor.stop() diff --git a/examples/pup/motor_pf/motor_pf_pwm.py b/examples/pup/motor_pf/motor_pf_pwm.py new file mode 100644 index 0000000..65c5bb0 --- /dev/null +++ b/examples/pup/motor_pf/motor_pf_pwm.py @@ -0,0 +1,25 @@ +from pybricks.pupdevices import ColorDistanceSensor, PFMotor +from pybricks.parameters import Port, Color, Direction +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorDistanceSensor(Port.B) + +# You can use multiple motors on different channels. +arm = PFMotor(sensor, 1, Color.BLUE) +wheel = PFMotor(sensor, 4, Color.RED, Direction.COUNTERCLOCKWISE) + +# Accelerate both motors. Only these values are available. +# Other values will be rounded down to the nearest match. +for duty in [15, 30, 45, 60, 75, 90, 100]: + arm.dc(duty) + wheel.dc(duty) + wait(1000) + +# To make the signal more reliable, there is a short +# pause between commands. So, they change speed and +# stop at a slightly different time. + +# Brake both motors. +arm.brake() +wheel.brake() diff --git a/examples/pup/sensor_color/color_ambient.py b/examples/pup/sensor_color/color_ambient.py new file mode 100644 index 0000000..731982e --- /dev/null +++ b/examples/pup/sensor_color/color_ambient.py @@ -0,0 +1,26 @@ +from pybricks.pupdevices import ColorSensor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorSensor(Port.A) + +# Repeat forever. +while True: + + # Get the ambient color values. Instead of scanning the color of a surface, + # this lets you scan the color of light sources like lamps or screens. + hsv = sensor.hsv(surface=False) + color = sensor.color(surface=False) + + # Get the ambient light intensity. + ambient = sensor.ambient() + + # Print the measurements. + print(hsv, color, ambient) + + # Point the sensor at a computer screen or colored light. Watch the color. + # Also, cover the sensor with your hands and watch the ambient value. + + # Wait so we can read the printed line + wait(100) diff --git a/examples/pup/sensor_color/color_print.py b/examples/pup/sensor_color/color_print.py new file mode 100644 index 0000000..5c6f467 --- /dev/null +++ b/examples/pup/sensor_color/color_print.py @@ -0,0 +1,20 @@ +from pybricks.pupdevices import ColorSensor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorSensor(Port.A) + +while True: + # Read the color and reflection + color = sensor.color() + reflection = sensor.reflection() + + # Print the measured color and reflection. + print(color, reflection) + + # Move the sensor around and see how + # well you can detect colors. + + # Wait so we can read the value. + wait(100) diff --git a/examples/pup/sensor_color/detectable_colors.py b/examples/pup/sensor_color/detectable_colors.py new file mode 100644 index 0000000..413c817 --- /dev/null +++ b/examples/pup/sensor_color/detectable_colors.py @@ -0,0 +1,39 @@ +from pybricks.pupdevices import ColorSensor +from pybricks.parameters import Port, Color +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorSensor(Port.A) + +# First, decide which objects you want to detect. +# Then measure their color with the hsv() method, +# as shown in the previous example. Write them down +# as shown below. The name is optional, but it is +# useful when you print the color value. +green = Color(h=132, s=94, v=26, name='GREEN_BRICK') +magenta = Color(h=348, s=96, v=40, name='MAGENTA_BRICK') +brown = Color(h=17, s=78, v=15, name='BROWN_BRICK') +red = Color(h=359, s=97, v=39, name='RED_BRICK') + +# Put your colors in a list or tuple. +# Including None is optional. Just omit it if +# you always want to get one of your colors. +my_colors = (green, magenta, brown, red, None) + +# Save your colors. +sensor.detectable_colors(my_colors) + +# color() works as usual, but it only +# returns one of your specified colors. +while True: + color = sensor.color() + + # Print the color. + print(color) + + # Check which one it is. + if color == magenta: + print("It works!") + + # Wait so we can read it. + wait(100) diff --git a/examples/pup/sensor_color/hsv.py b/examples/pup/sensor_color/hsv.py new file mode 100644 index 0000000..4c60d15 --- /dev/null +++ b/examples/pup/sensor_color/hsv.py @@ -0,0 +1,21 @@ +from pybricks.pupdevices import ColorSensor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorSensor(Port.A) + +while True: + # The standard color() method always "rounds" the + # measurement to the nearest "whole" color. + # That's useful for most applications. + + # But you can get the original hue, saturation, + # and value without "rounding", as follows: + color = sensor.hsv() + + # Print the results. + print(color) + + # Wait so we can read the value. + wait(500) diff --git a/examples/pup/sensor_color/lights_blink.py b/examples/pup/sensor_color/lights_blink.py new file mode 100644 index 0000000..08c72b3 --- /dev/null +++ b/examples/pup/sensor_color/lights_blink.py @@ -0,0 +1,27 @@ +from pybricks.pupdevices import ColorSensor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorSensor(Port.A) + +# Repeat forever. +while True: + + # Turn on one light at a time, at half the brightness. + # Do this for all 3 lights and repeat that 5 times. + for i in range(5): + sensor.lights.on(50, 0, 0) + wait(100) + sensor.lights.on(0, 50, 0) + wait(100) + sensor.lights.on(0, 0, 50) + wait(100) + + # Turn all lights on at maximum brightness. + sensor.lights.on(100) + wait(500) + + # Turn all lights off. + sensor.lights.off() + wait(500) diff --git a/examples/pup/sensor_color/wait_for_color.py b/examples/pup/sensor_color/wait_for_color.py new file mode 100644 index 0000000..aa6b58e --- /dev/null +++ b/examples/pup/sensor_color/wait_for_color.py @@ -0,0 +1,27 @@ +from pybricks.pupdevices import ColorSensor +from pybricks.parameters import Port, Color +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorSensor(Port.A) + + +# This is a function that waits for a desired color. +def wait_for_color(desired_color): + # While the color is not the desired color, we keep waiting. + while sensor.color() != desired_color: + wait(20) + + +# Now we use the function we just created above. +while True: + + # Here you can make your train/vehicle go forward. + + print("Waiting for red ...") + wait_for_color(Color.RED) + + # Here you can make your train/vehicle go backward. + + print("Waiting for blue ...") + wait_for_color(Color.BLUE) diff --git a/examples/pup/sensor_color_distance/color_print.py b/examples/pup/sensor_color_distance/color_print.py new file mode 100644 index 0000000..b744468 --- /dev/null +++ b/examples/pup/sensor_color_distance/color_print.py @@ -0,0 +1,19 @@ +from pybricks.pupdevices import ColorDistanceSensor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorDistanceSensor(Port.A) + +while True: + # Read the color. + color = sensor.color() + + # Print the measured color. + print(color) + + # Move the sensor around and see how + # well you can detect colors. + + # Wait so we can read the value. + wait(100) diff --git a/examples/pup/sensor_color_distance/detectable_colors.py b/examples/pup/sensor_color_distance/detectable_colors.py new file mode 100644 index 0000000..51f5bd7 --- /dev/null +++ b/examples/pup/sensor_color_distance/detectable_colors.py @@ -0,0 +1,39 @@ +from pybricks.pupdevices import ColorDistanceSensor +from pybricks.parameters import Port, Color +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorDistanceSensor(Port.A) + +# First, decide which objects you want to detect. +# Then measure their color with the hsv() method, +# as shown in the previous example. Write them down +# as shown below. The name is optional, but it is +# useful when you print the color value. +green = Color(h=132, s=94, v=26, name='GREEN_BRICK') +magenta = Color(h=348, s=96, v=40, name='MAGENTA_BRICK') +brown = Color(h=17, s=78, v=15, name='BROWN_BRICK') +red = Color(h=359, s=97, v=39, name='RED_BRICK') + +# Put your colors in a list or tuple. +# Including None is optional. Just omit it if +# you always want to get one of your colors. +my_colors = (green, magenta, brown, red, None) + +# Save your colors. +sensor.detectable_colors(my_colors) + +# color() works as usual, but it only +# returns one of your specified colors. +while True: + color = sensor.color() + + # Print the color. + print(color) + + # Check which one it is. + if color == magenta: + print("It works!") + + # Wait so we can read it. + wait(100) diff --git a/examples/pup/sensor_color_distance/distance_blink.py b/examples/pup/sensor_color_distance/distance_blink.py new file mode 100644 index 0000000..ce2f505 --- /dev/null +++ b/examples/pup/sensor_color_distance/distance_blink.py @@ -0,0 +1,23 @@ +from pybricks.pupdevices import ColorDistanceSensor +from pybricks.parameters import Port, Color +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorDistanceSensor(Port.A) + +# Repeat forever. +while True: + + # If the sensor sees an object nearby. + if sensor.distance() <= 40: + + # Then blink the light red/blue 5 times. + for i in range(5): + sensor.light.on(Color.RED) + wait(30) + sensor.light.on(Color.BLUE) + wait(30) + else: + # If the sensor sees nothing + # nearby, just wait briefly. + wait(10) diff --git a/examples/pup/sensor_color_distance/hsv.py b/examples/pup/sensor_color_distance/hsv.py new file mode 100644 index 0000000..a41a2b9 --- /dev/null +++ b/examples/pup/sensor_color_distance/hsv.py @@ -0,0 +1,21 @@ +from pybricks.pupdevices import ColorDistanceSensor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorDistanceSensor(Port.A) + +while True: + # The standard color() method always "rounds" the + # measurement to the nearest "whole" color. + # That's useful for most applications. + + # But you can get the original hue, saturation, + # and value without "rounding", as follows: + color = sensor.hsv() + + # Print the results. + print(color) + + # Wait so we can read the value. + wait(500) diff --git a/examples/pup/sensor_color_distance/wait_for_color.py b/examples/pup/sensor_color_distance/wait_for_color.py new file mode 100644 index 0000000..04534b4 --- /dev/null +++ b/examples/pup/sensor_color_distance/wait_for_color.py @@ -0,0 +1,27 @@ +from pybricks.pupdevices import ColorDistanceSensor +from pybricks.parameters import Port, Color +from pybricks.tools import wait + +# Initialize the sensor. +sensor = ColorDistanceSensor(Port.A) + + +# This is a function that waits for a desired color. +def wait_for_color(desired_color): + # While the color is not the desired color, we keep waiting. + while sensor.color() != desired_color: + wait(20) + + +# Now we use the function we just created above. +while True: + + # Here you can make your train/vehicle go forward. + + print("Waiting for red ...") + wait_for_color(Color.RED) + + # Here you can make your train/vehicle go backward. + + print("Waiting for blue ...") + wait_for_color(Color.BLUE) diff --git a/examples/pup/sensor_force/basics.py b/examples/pup/sensor_force/basics.py new file mode 100644 index 0000000..b979603 --- /dev/null +++ b/examples/pup/sensor_force/basics.py @@ -0,0 +1,21 @@ +from pybricks.pupdevices import ForceSensor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the sensor. +button = ForceSensor(Port.A) + +while True: + # Read all the information we can get from this sensor. + force = button.force() + dist = button.distance() + press = button.pressed() + touch = button.touched() + + # Print the values + print("Force", force, "Dist:", dist, "Pressed:", press, "Touched:", touch) + + # Push the sensor button see what happens to the values. + + # Wait some time so we can read what is printed. + wait(200) diff --git a/examples/pup/sensor_force/peak.py b/examples/pup/sensor_force/peak.py new file mode 100644 index 0000000..026ea25 --- /dev/null +++ b/examples/pup/sensor_force/peak.py @@ -0,0 +1,45 @@ +from pybricks.pupdevices import ForceSensor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the sensor. +button = ForceSensor(Port.A) + + +# This function waits until the button is pushed. It keeps track of the maximum +# detected force until the button is released. Then it returns the maximum. +def wait_for_force(): + + # Wait for a force, by doing nothing for as long the force is nearly zero. + print("Waiting for force.") + while button.force() <= 0.1: + wait(10) + + # Now we wait for the release, by waiting for the force to be zero again. + print("Waiting for release.") + + # While we wait for that to happen, we keep reading the force and remember + # the maximum force. We do this by initializing the maximum at 0, and + # updating it each time we detect a bigger force. + maximum = 0 + force = 10 + while force > 0.1: + # Read the force. + force = button.force() + + # Update the maximum if the measured force is larger. + if force > maximum: + maximum = force + + # Wait and then measure again. + wait(10) + + # Return the maximum force. + return maximum + + +# Keep waiting for the sensor button to be pushed. When it is, display +# the peak force and repeat. +while True: + peak = wait_for_force() + print("Released. Peak force: {0} N\n".format(peak)) diff --git a/examples/pup/sensor_infrared/basics.py b/examples/pup/sensor_infrared/basics.py new file mode 100644 index 0000000..0b1bd3c --- /dev/null +++ b/examples/pup/sensor_infrared/basics.py @@ -0,0 +1,21 @@ +from pybricks.pupdevices import InfraredSensor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the sensor. +ir = InfraredSensor(Port.A) + +while True: + # Read all the information we can get from this sensor. + dist = ir.distance() + count = ir.count() + ref = ir.reflection() + + # Print the values + print("Distance:", dist, "Count:", count, "Reflection:", ref) + + # Move the sensor around and move your hands in front + # of it to see what happens to the values. + + # Wait some time so we can read what is printed. + wait(200) diff --git a/examples/pup/sensor_tilt/basics.py b/examples/pup/sensor_tilt/basics.py new file mode 100644 index 0000000..6b1f6c7 --- /dev/null +++ b/examples/pup/sensor_tilt/basics.py @@ -0,0 +1,16 @@ +from pybricks.pupdevices import TiltSensor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the sensor. +accel = TiltSensor(Port.A) + +while True: + # Read the tilt angles relative to the horizontal plane. + pitch, roll = accel.tilt() + + # Print the values + print("Pitch:", pitch, "Roll:", roll) + + # Wait some time so we can read what is printed. + wait(100) diff --git a/examples/pup/sensor_ultrasonic/basics.py b/examples/pup/sensor_ultrasonic/basics.py new file mode 100644 index 0000000..9dd4a9e --- /dev/null +++ b/examples/pup/sensor_ultrasonic/basics.py @@ -0,0 +1,21 @@ +from pybricks.pupdevices import UltrasonicSensor +from pybricks.parameters import Port +from pybricks.tools import wait + +# Initialize the sensor. +eyes = UltrasonicSensor(Port.A) + +while True: + # Print the measured distance. + print(eyes.distance()) + + # If an object is detected closer than 500mm: + if eyes.distance() < 500: + # Turn the lights on. + eyes.lights.on(100) + else: + # Turn the lights off. + eyes.lights.off() + + # Wait some time so we can read what is printed. + wait(100) diff --git a/examples/pup/sensor_ultrasonic/math.py b/examples/pup/sensor_ultrasonic/math.py new file mode 100644 index 0000000..dde1825 --- /dev/null +++ b/examples/pup/sensor_ultrasonic/math.py @@ -0,0 +1,32 @@ +from pybricks.pupdevices import UltrasonicSensor +from pybricks.parameters import Port +from pybricks.tools import wait, StopWatch + +# The math module is part of standard MicroPython: +# https://docs.micropython.org/en/latest/library/math.html +from math import pi, sin + +# Initialize the sensor. +eyes = UltrasonicSensor(Port.A) + +# Initialize a timer. +watch = StopWatch() + +# We want one full light cycle to last three seconds. +PERIOD = 3000 + +while True: + # The phase is where we are in the unit circle now. + phase = watch.time()/PERIOD*2*pi + + # Each light follows a sine wave with a mean of 50, with an amplitude of 50. + # We offset this sine wave by 90 degrees for each light, so that all the + # lights do something different. + brightness = [sin(phase + offset*pi/2) * 50 + 50 for offset in range(4)] + + # Set the brightness values for all lights. The * symbol unpacks the list + # of brightness values into separate arguments. + eyes.lights.on(*brightness) + + # Wait some time. + wait(50)