Skip to content

Commit 9fc01f8

Browse files
committed
Ported examples from CircuitPython and added a few more
1 parent 4cb3e6d commit 9fc01f8

File tree

5 files changed

+231
-29
lines changed

5 files changed

+231
-29
lines changed

Examples/drive_examples.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from XRPLib.defaults import *
2+
import time
3+
4+
"""
5+
By the end of this file students will learn how to control the drivetrain,
6+
both by setting effort values directly to the motors and by using go_straight and go_turn
7+
"""
8+
9+
# drive straight for a set time period (defualt 1 second)
10+
def drive_straight(drive_time: float = 1):
11+
drivetrain.set_effort(0.8, 0.8)
12+
time.sleep(drive_time)
13+
drivetrain.stop()
14+
15+
# drive at a slight counter clockwise arc for a set time period (default 1 second)
16+
def arc_turn(turn_time: float = 1):
17+
drivetrain.set_effort(0.5, 0.8)
18+
time.sleep(turn_time)
19+
drivetrain.stop()
20+
21+
# turn CCW at a point for a set time period (default 1 second)
22+
def point_turn(turn_time: float = 1):
23+
drivetrain.set_effort(-0.8, 0.8)
24+
time.sleep(turn_time)
25+
drivetrain.stop()
26+
27+
# pivot turn around the left wheel for a set time period (default 1 second)
28+
def swing_turn(turn_time: float = 1):
29+
drivetrain.set_effort(0, 0.8)
30+
time.sleep(turn_time)
31+
drivetrain.stop()
32+
33+
# Driving in a circle by setting a difference in motor efforts
34+
def circle():
35+
while True:
36+
drivetrain.set_effort(0.8, 1)
37+
38+
# Follow the perimeter of a square with variable sidelength
39+
def square(sidelength):
40+
for sides in range(4):
41+
drivetrain.straight(sidelength, 80)
42+
drivetrain.turn(90)
43+
# Alternatively:
44+
# polygon(sidelength, 4)
45+
46+
# Follow the perimeter of an arbitrary polygon with variable side length and number of sides
47+
# Side length in centimeters
48+
def polygon(side_length, number_of_sides):
49+
for s in range(number_of_sides):
50+
drivetrain.straight(side_length)
51+
drivetrain.turn(360/number_of_sides)
52+
53+
# A slightly longer example program showing how a robot may follow a simple path
54+
def test_drive():
55+
print("Driving forward 25cm")
56+
drivetrain.straight(25, 0.8)
57+
58+
time.sleep(1)
59+
60+
print("turn 90 degrees right")
61+
drivetrain.turn(90,0.8)
62+
63+
time.sleep(1)
64+
65+
print("turn 90 degrees left by setting speed negative")
66+
drivetrain.turn(90, -0.8)
67+
68+
time.sleep(1)
69+
70+
print("drive backwards 25 cm by setting distance negative")
71+
# There is no difference between setting speed or distance negative, both work
72+
drivetrain.straight(-25,0.8)

Examples/misc_examples.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from XRPLib.defaults import *
2+
from .drive_examples import test_drive
3+
import time
4+
5+
"""
6+
By the end of this file students will learn how to use the on-board buttons and LEDS,
7+
as well as control a servo that may be connected.
8+
"""
9+
10+
# Does nothing until any button input is found
11+
def wait_for_button():
12+
print("Waiting for button signal from either button")
13+
14+
# Wait until user command before running
15+
while not board.is_button_pressed():
16+
time.sleep(.01)
17+
18+
# Wait until user to release button before running
19+
while board.is_button_pressed():
20+
time.sleep(.01)
21+
22+
print("Button input found; Program starting")
23+
24+
def test_leds():
25+
board.led_blink(3)
26+
time.sleep(1)
27+
board.led_off()
28+
29+
# Test moving to both extremes of the servo motion and some middle value
30+
def test_servo():
31+
servo_one.set_angle(135)
32+
time.sleep(2)
33+
servo_one.set_angle(0)
34+
time.sleep(2)
35+
servo_one.set_angle(60)
36+
time.sleep(2)
37+
38+
# Installation Verification Program
39+
def ivp():
40+
while not board.is_button_pressed():
41+
print(f"Left Reflectance: {reflectance.get_left()}, Right Reflectance: {reflectance.get_right()}")
42+
time.sleep(0.1)
43+
while board.is_button_pressed():
44+
time.sleep(.01)
45+
while not board.is_button_pressed():
46+
print(f"Ultrasonic Distance: {rangefinder.distance()}")
47+
time.sleep(0.1)
48+
while board.is_button_pressed():
49+
time.sleep(.01)
50+
print("Testing Servo")
51+
test_servo()
52+
print("Testing LEDs")
53+
wait_for_button()
54+
test_leds()
55+
print("Testing Drivetrain:")
56+
wait_for_button()
57+
test_drive()

Examples/sensor_examples.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
from XRPLib.defaults import *
2+
import time
3+
4+
"""
5+
By the end of this file students will learn how to read and use data from
6+
both the ultrasonic sensors and the line followers.
7+
They will also have a chance to learn the basics of proportional control.
8+
"""
9+
10+
# Polling data from the ultrasonic sensor
11+
def ultrasonic_test():
12+
while True:
13+
print(rangefinder.distance())
14+
time.sleep(0.1)
15+
16+
# Approaches a wall at a set speed and then stops
17+
def drive_till_close(target_distance: float = 10.0):
18+
speed = 0.6
19+
while rangefinder.distance() > target_distance:
20+
drivetrain.set_effort(speed, speed)
21+
time.sleep(0.01)
22+
drivetrain.set_effort(0, 0)
23+
24+
# Maintains a certain distance from the wall using proportional control
25+
def standoff(target_distance: float = 10.0):
26+
KP = 0.2
27+
while True:
28+
distance = rangefinder.distance()
29+
error = distance - target_distance
30+
drivetrain.set_effort(error * KP, error*KP)
31+
time.sleep(0.01)
32+
33+
# Maintains a certain distance from the wall while driving
34+
# using proportional control (sensor on right side of robot this time)
35+
def wall_follow(target_distance: float = 10.0):
36+
KP = 0.1
37+
base_speed = 0.5
38+
while True:
39+
distance = rangefinder.distance()
40+
error = distance - target_distance
41+
print(error)
42+
drivetrain.set_effort(base_speed + error * KP, base_speed - error*KP)
43+
time.sleep(0.01)
44+
45+
# Follows a line using the line followers
46+
def line_track():
47+
base_effort = 0.6
48+
KP = 0.6
49+
while True:
50+
# You always want to take the difference of the sensors because the raw value isn't always consistent.
51+
error = reflectance.get_left() - reflectance.get_right()
52+
print(error)
53+
drivetrain.set_effort(base_effort - error * KP, base_effort + error * KP)
54+
time.sleep(0.01)
55+
56+
# Polling data from the IMU
57+
def imu_test():
58+
while True:
59+
print(f"Pitch: {imu.get_pitch()}, Heading: {imu.get_heading()}, Roll: {imu.get_yaw()}, Accelerometer output: {imu.get_acc_rates()}")
60+
time.sleep(0.1)
61+
62+
def climb_ramp(ramp_angle, angle_tolerance=3.5):
63+
speed = 0.6
64+
# Find ramp by driving forward
65+
while imu.get_pitch() < ramp_angle-angle_tolerance:
66+
drivetrain.set_effort(speed, speed)
67+
time.sleep(0.05)
68+
# Drive up ramp until angle levels out again
69+
while imu.get_pitch() >= ramp_angle-angle_tolerance:
70+
drivetrain.set_effort(speed, speed)
71+
time.sleep(0.05)
72+
# Then stop
73+
drivetrain.set_effort(0, 0)
File renamed without changes.

XRPLib/imu.py

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -117,24 +117,6 @@ def _mg(self, reg):
117117
def _mdps(self, reg):
118118
return round(self._int16(self._get2reg(reg)) * 4.375 * self._scale_g_c)
119119

120-
def _get_acc_x_rate(self):
121-
"""
122-
Individual axis read for the Accelerometer's X-axis, in mg
123-
"""
124-
return self._mg(LSM6DSO_OUTX_L_A) - self.acc_offsets[0]
125-
126-
def _get_acc_y_rate(self):
127-
"""
128-
Individual axis read for the Accelerometer's Y-axis, in mg
129-
"""
130-
return self._mg(LSM6DSO_OUTY_L_A) - self.acc_offsets[1]
131-
132-
def _get_acc_z_rate(self):
133-
"""
134-
Individual axis read for the Accelerometer's Z-axis, in mg
135-
"""
136-
return self._mg(LSM6DSO_OUTZ_L_A) - self.acc_offsets[2]
137-
138120
def _get_gyro_x_rate(self):
139121
"""
140122
Individual axis read for the Gyroscope's X-axis, in mg
@@ -153,16 +135,6 @@ def _get_gyro_z_rate(self):
153135
"""
154136
return self._mdps(LSM6DSO_OUTZ_L_G) - self.gyro_offsets[2]
155137

156-
def _get_acc_rates(self):
157-
"""
158-
Retrieves the array of readings from the Accelerometer, in mg
159-
The order of the values is x, y, z.
160-
"""
161-
self.irq_v[0][0] = self._get_acc_x_rate()
162-
self.irq_v[0][1] = self._get_acc_y_rate()
163-
self.irq_v[0][2] = self._get_acc_z_rate()
164-
return self.irq_v[0]
165-
166138
def _get_gyro_rates(self):
167139
"""
168140
Retrieves the array of readings from the Gyroscope, in mdps
@@ -179,13 +151,41 @@ def _get_acc_gyro_rates(self):
179151
The first row is the acceleration values, the second row is the gyro values.
180152
The order of the values is x, y, z.
181153
"""
182-
self._get_acc_rates()
154+
self.get_acc_rates()
183155
self._get_gyro_rates()
184156
return self.irq_v
185157

186158
"""
187159
Public facing API Methods
188160
"""
161+
162+
def get_acc_x(self):
163+
"""
164+
Individual axis read for the Accelerometer's X-axis, in mg
165+
"""
166+
return self._mg(LSM6DSO_OUTX_L_A) - self.acc_offsets[0]
167+
168+
def get_acc_y(self):
169+
"""
170+
Individual axis read for the Accelerometer's Y-axis, in mg
171+
"""
172+
return self._mg(LSM6DSO_OUTY_L_A) - self.acc_offsets[1]
173+
174+
def get_acc_z(self):
175+
"""
176+
Individual axis read for the Accelerometer's Z-axis, in mg
177+
"""
178+
return self._mg(LSM6DSO_OUTZ_L_A) - self.acc_offsets[2]
179+
180+
def get_acc_rates(self):
181+
"""
182+
Retrieves the array of readings from the Accelerometer, in mg
183+
The order of the values is x, y, z.
184+
"""
185+
self.irq_v[0][0] = self.get_acc_x()
186+
self.irq_v[0][1] = self.get_acc_y()
187+
self.irq_v[0][2] = self.get_acc_z()
188+
return self.irq_v[0]
189189

190190
def get_pitch(self):
191191
"""

0 commit comments

Comments
 (0)