Skip to content

Commit 1cee781

Browse files
committed
bricks/ev3: Add Motor Control on apps tab.
1 parent d4225bb commit 1cee781

10 files changed

Lines changed: 736 additions & 0 deletions

File tree

bricks/_common/micropython.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ pbio_error_t pbsys_main_program_validate(pbsys_main_program_t *program) {
306306
return PBIO_SUCCESS;
307307
#endif
308308
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_EV3_APPS
309+
case PBIO_PYBRICKS_USER_PROGRAM_ID_EV3_MOTOR_CONTROL:
310+
return PBIO_SUCCESS;
309311
#endif
310312
default:
311313
return PBIO_ERROR_NOT_SUPPORTED;
@@ -398,6 +400,10 @@ void pbsys_main_run_program(pbsys_main_program_t *program) {
398400
#endif
399401

400402
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_EV3_APPS
403+
case PBIO_PYBRICKS_USER_PROGRAM_ID_EV3_MOTOR_CONTROL:
404+
pb_package_pybricks_init(false);
405+
pyexec_frozen_module("_ev3_motor_control.py", false);
406+
break;
401407
#endif
402408

403409
default:

bricks/ev3/manifest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
include("../_common/manifest.py")
2+
freeze_as_mpy("../ev3/modules", "_ev3_motor_control.py")
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
from pybricks.tools import wait
2+
from pybricks.parameters import ImageFile, Button, Port, Color
3+
from pybricks.hubs import EV3Brick
4+
from pybricks.ev3devices import Motor
5+
6+
ev3 = EV3Brick()
7+
8+
# True means A&D pair is active. False means B&C pair is active.
9+
pair_ad_active = False
10+
11+
# Re-index motors by port for re-initialization on the fly.
12+
motors = {
13+
Port.A: None,
14+
Port.B: None,
15+
Port.C: None,
16+
Port.D: None,
17+
}
18+
19+
POWER = 100
20+
21+
# Preload to avoid repeated allocation.
22+
IMG_POS = ImageFile._ROTATE_CW18
23+
IMG_NEG = ImageFile._ROTATE_CCW18
24+
IMG_AD = ImageFile._APP_MOTOR_CONTROL_AD
25+
IMG_BC = ImageFile._APP_MOTOR_CONTROL_BC
26+
27+
28+
# Wrapper to set DC and reinitialize motor on the fly.
29+
def set_dc(port, dc):
30+
# If there was a motor, close if it got unplugged.
31+
if motors[port] is not None:
32+
try:
33+
motors[port].angle()
34+
except OSError:
35+
motors[port].close()
36+
motors[port] = None
37+
pass
38+
39+
# If there isn't a motor, try to initialize it now.
40+
if motors[port] is None:
41+
try:
42+
motors[port] = Motor(port)
43+
except OSError:
44+
pass
45+
46+
# Drive the motor if there is one.
47+
if motors[port]:
48+
try:
49+
motors[port].dc(dc)
50+
# On success, indicate the active direction on the display.
51+
image = IMG_POS if dc > 0 else IMG_NEG if dc < 0 else None
52+
if image:
53+
index = ord(repr(port)[5]) - ord("A")
54+
ev3.screen.draw_image(20 + index * 40, 2, image)
55+
except OSError:
56+
motors[port].close()
57+
motors[port] = None
58+
59+
60+
def draw_ui():
61+
ev3.screen.clear()
62+
file = IMG_AD if pair_ad_active else IMG_BC
63+
ev3.screen.draw_image(0, 20, file)
64+
ev3.screen.draw_box(0, 0, 177, 16, fill=True, color=Color.WHITE)
65+
66+
67+
while True:
68+
draw_ui()
69+
ev3.light.on(Color.GREEN)
70+
71+
# Wait for anything to happen
72+
while not (pressed := ev3.buttons.pressed()):
73+
wait(10)
74+
75+
# Center button toggles motor pair
76+
if Button.CENTER in pressed:
77+
pair_ad_active = not pair_ad_active
78+
draw_ui()
79+
while any(ev3.buttons.pressed()):
80+
wait(10)
81+
continue
82+
83+
# Determine motor power for vertical buttons.
84+
vertical_dc = 0
85+
if Button.UP in pressed:
86+
vertical_dc += POWER
87+
if Button.DOWN in pressed:
88+
vertical_dc -= POWER
89+
90+
# Determine motor power for horizontal buttons.
91+
horizontal_dc = 0
92+
if Button.RIGHT in pressed:
93+
horizontal_dc += POWER
94+
if Button.LEFT in pressed:
95+
horizontal_dc -= POWER
96+
97+
# Activity heartbeat
98+
ev3.light.blink(Color.GREEN, [100, 100, 800, 100])
99+
100+
# Drive one or two motors.
101+
set_dc(Port.A if pair_ad_active else Port.B, vertical_dc)
102+
set_dc(Port.D if pair_ad_active else Port.C, horizontal_dc)
103+
104+
# Keep going until button state changes.
105+
while ev3.buttons.pressed() == pressed:
106+
wait(10)
107+
108+
# Stop all motors.
109+
for motor in motors.values():
110+
try:
111+
motor.stop()
112+
except (OSError, AttributeError):
113+
pass

bricks/virtualhub/manifest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
include("../_common/manifest.py")
2+
freeze_as_mpy("../ev3/modules", "_ev3_motor_control.py")

lib/pbio/include/pbio/protocol.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ typedef enum {
6969
* data persistently on the hub.
7070
*/
7171
PBIO_PYBRICKS_USER_PROGRAM_ID_IMU_CALIBRATION = 130,
72+
/**
73+
* Program to control EV3 motors with the buttons.
74+
*/
75+
PBIO_PYBRICKS_USER_PROGRAM_ID_EV3_MOTOR_CONTROL = 133,
7276
} pbio_pybricks_user_program_id_t;
7377

7478
/**
54.5 KB
Binary file not shown.
54.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)