Skip to content

Commit 249691c

Browse files
committed
Add showcase example for inventor
1 parent 66e8d70 commit 249691c

File tree

2 files changed

+181
-1
lines changed

2 files changed

+181
-1
lines changed

micropython/examples/inventor/motors/driving_sequence.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
board.motors[LEFT].direction(REVERSED_DIR)
5050
board.encoders[LEFT].direction(REVERSED_DIR)
5151

52-
# Create PID objects for position control
52+
# Create PID objects for velocity control
5353
vel_pids = [PID(VEL_KP, VEL_KI, VEL_KD, UPDATE_RATE) for i in range(NUM_MOTORS)]
5454

5555

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import time
2+
from pimoroni import PID, REVERSED_DIR
3+
from inventor import Inventor, MOTOR_A, MOTOR_B, NUM_MOTORS, NUM_LEDS, GP0
4+
from aye_arr.nec import NECReceiver
5+
from aye_arr.nec.remotes import PimoroniRemote
6+
7+
8+
"""
9+
A demonstration of driving both of Inventor 2040 W's motor outputs through a
10+
sequence of velocities, with the help of their attached encoders and PID control.
11+
12+
Press "User" to exit the program.
13+
"""
14+
15+
# Wheel friendly names
16+
LEFT = MOTOR_A
17+
RIGHT = MOTOR_B
18+
NAMES = ["LEFT", "RIGHT"]
19+
20+
# Constants
21+
UPDATES = 100 # How many times to update the motor per second
22+
UPDATE_RATE = 1 / UPDATES
23+
PRINT_DIVIDER = 4 # How many of the updates should be printed (i.e. 2 would be every other update)
24+
25+
# Motor Constnats
26+
GEAR_RATIO = 50 # The gear ratio of the motors
27+
SPEED_SCALE = 5.4 # The scaling to apply to each motor's speed to match its real-world speed
28+
DRIVING_SPEED = 1.0 # The speed to drive the wheels at, for forward-backward. From 0.0 to SPEED_SCALE
29+
TURNING_SPEED = 0.5 # The speed to drive the wheels at, for left-right. From 0.0 to SPEED_SCALE
30+
31+
# Motor PID values
32+
VEL_KP = 30.0 # Velocity proportional (P) gain
33+
VEL_KI = 0.0 # Velocity integral (I) gain
34+
VEL_KD = 0.4 # Velocity derivative (D) gain
35+
36+
# Servo Constants (These values will be unique for each servo)
37+
GRIPPER_OPEN_PULSE = 1960 # The pulse width (in microseconds) to put the gripper in the open position
38+
GRIPPER_CLOSED_PULSE = 1040 # The pulse width (in microseconds) to put the gripper in the closed position
39+
GRIPPER_STEP = 0.1 # The percentage to move the gripper by when the button is pressed
40+
41+
# LED Constants
42+
BRIGHTNESS = 0.5 # The brightness of the LEDs, from 0 to 1
43+
RED = 255, 0, 0
44+
GREEN = 0, 255, 0
45+
BLUE = 0, 0, 255
46+
CYAN = 0, 255, 255
47+
MAGENTA = 255, 0, 255
48+
YELLOW = 255, 255, 0
49+
WARM_WHITE = 255, 192, 96
50+
WHITE = 255, 255, 255
51+
COOL_WHITE = 96, 192, 255
52+
BLACK = 0, 0, 0
53+
54+
55+
# Create a new Inventor object
56+
board = Inventor(motor_gear_ratio=GEAR_RATIO)
57+
58+
# Set the speed scale of the motors
59+
board.motors[LEFT].speed_scale(SPEED_SCALE)
60+
board.motors[RIGHT].speed_scale(SPEED_SCALE)
61+
62+
# Reverse the direction of the left motor and encoder
63+
board.motors[LEFT].direction(REVERSED_DIR)
64+
board.encoders[LEFT].direction(REVERSED_DIR)
65+
66+
# Create PID objects for velocity control
67+
vel_pids = [PID(VEL_KP, VEL_KI, VEL_KD, UPDATE_RATE) for i in range(NUM_MOTORS)]
68+
69+
# Set up the first servo for the gripper
70+
gripper = board.servos[0]
71+
cal = gripper.calibration()
72+
cal.apply_two_pairs(GRIPPER_CLOSED_PULSE, GRIPPER_OPEN_PULSE, 0, 1)
73+
gripper.calibration(cal)
74+
75+
76+
# Functions for driving in common directions
77+
def drive_fwd_back(speed):
78+
vel_pids[LEFT].setpoint = speed
79+
vel_pids[RIGHT].setpoint = speed
80+
81+
82+
def turn_left_right(speed):
83+
vel_pids[LEFT].setpoint = -speed
84+
vel_pids[RIGHT].setpoint = speed
85+
86+
87+
def stop_driving():
88+
vel_pids[LEFT].setpoint = 0
89+
vel_pids[RIGHT].setpoint = 0
90+
91+
92+
# Function for operating the gripper servo
93+
def move_gripper(step):
94+
val = max(min(gripper.value() + step, 1), 0)
95+
gripper.value(val)
96+
97+
98+
# Functions for setting LED colours
99+
def set_all_leds(colour):
100+
r = int(colour[0] * BRIGHTNESS)
101+
g = int(colour[1] * BRIGHTNESS)
102+
b = int(colour[2] * BRIGHTNESS)
103+
for i in range(NUM_LEDS):
104+
board.leds.set_rgb(i, r, g, b)
105+
106+
107+
def set_rainbow():
108+
for i in range(NUM_LEDS):
109+
hue = float(i) / NUM_LEDS
110+
board.leds.set_hsv(i, hue, 1.0, BRIGHTNESS)
111+
112+
113+
# Bind functions to each of the Pimoroni remote's buttons.
114+
# Releasing a direction button will the robot to stop driving
115+
remote = PimoroniRemote()
116+
remote.bind("UP", (drive_fwd_back, DRIVING_SPEED), on_release=stop_driving)
117+
remote.bind("DOWN", (drive_fwd_back, -DRIVING_SPEED), on_release=stop_driving)
118+
remote.bind("LEFT", (turn_left_right, TURNING_SPEED), on_release=stop_driving)
119+
remote.bind("RIGHT", (turn_left_right, -TURNING_SPEED), on_release=stop_driving)
120+
remote.bind("ANTICLOCK", (move_gripper, GRIPPER_STEP))
121+
remote.bind("CLOCKWISE", (move_gripper, -GRIPPER_STEP))
122+
remote.bind("OK/STOP", (set_all_leds, BLACK))
123+
remote.bind("1/RED", (set_all_leds, RED))
124+
remote.bind("2/GREEN", (set_all_leds, GREEN))
125+
remote.bind("3/BLUE", (set_all_leds, BLUE))
126+
remote.bind("4/CYAN", (set_all_leds, CYAN))
127+
remote.bind("5/MAGENTA", (set_all_leds, MAGENTA))
128+
remote.bind("6/YELLOW", (set_all_leds, YELLOW))
129+
remote.bind("7/WARM", (set_all_leds, WARM_WHITE))
130+
remote.bind("8/WHITE", (set_all_leds, WHITE))
131+
remote.bind("9/COOL", (set_all_leds, COOL_WHITE))
132+
remote.bind("0/RAINBOW", set_rainbow)
133+
134+
135+
# Set up the IR receiver on GP0, using PIO 1 and SM 0
136+
receiver = NECReceiver(GP0, 1, 0)
137+
receiver.bind(remote)
138+
139+
# Variables
140+
captures = [None] * NUM_MOTORS
141+
142+
try:
143+
# Enable the motors and servo to get started
144+
for m in board.motors:
145+
m.enable()
146+
gripper.enable()
147+
148+
# Start listening for IR remote signals
149+
receiver.start()
150+
151+
# Continually move the motor until the user switch is pressed
152+
while not board.switch_pressed():
153+
154+
# Decode any received IR signals from since we last checked
155+
receiver.decode()
156+
157+
# Capture the state of all the encoders
158+
for i in range(NUM_MOTORS):
159+
captures[i] = board.encoders[i].capture()
160+
161+
for i in range(NUM_MOTORS):
162+
# Calculate the acceleration to apply to the motor to move it closer to the velocity setpoint
163+
accel = vel_pids[i].calculate(captures[i].revolutions_per_second)
164+
165+
# Accelerate or decelerate the motor
166+
board.motors[i].speed(board.motors[i].speed() + (accel * UPDATE_RATE))
167+
168+
time.sleep(UPDATE_RATE)
169+
170+
finally:
171+
# Stop the motors and servo
172+
for m in board.motors:
173+
m.disable()
174+
gripper.disable()
175+
176+
# Turn off the LED bars
177+
board.leds.clear()
178+
179+
# Stop the IR receiver
180+
receiver.stop()

0 commit comments

Comments
 (0)