Compare commits

...

59 Commits

Author SHA1 Message Date
90a1c03a5c :sparkles 2022-11-07 14:08:25 +01:00
30213107de :sparkles 2022-11-07 14:07:53 +01:00
78e76da161 :sparkles 2022-11-07 12:09:03 +01:00
1c79989840 :sparkles 2022-11-07 12:07:02 +01:00
90b5ff824d :sparkles 2022-11-07 12:06:27 +01:00
144551df39 2022-11-02 15:26:39 +01:00
e18767fcb6 2022-11-02 15:23:54 +01:00
919b7b2c4d 2022-11-02 15:22:35 +01:00
b30833dcae 2022-11-02 15:15:26 +01:00
12bcfe412f 2022-11-02 15:12:29 +01:00
374c321c4c 2022-11-02 15:08:31 +01:00
e974a0bb27 2022-11-02 15:05:39 +01:00
f7d459482a 2022-11-02 15:05:02 +01:00
073897c485 2022-11-02 15:01:03 +01:00
76a459fc9f 2022-11-02 14:58:55 +01:00
b0bd525726 2022-11-02 14:54:07 +01:00
c70da77fc9 2022-11-02 14:49:30 +01:00
60dbadabe1 2022-11-02 14:49:02 +01:00
bcf1ae2a5a 2022-11-02 14:46:59 +01:00
82e4c2eb43 2022-11-02 14:45:46 +01:00
02c2c04ca4 2022-11-02 14:43:44 +01:00
5fdcf1c0dc 2022-11-02 14:27:43 +01:00
71b7c67fff 2022-11-02 14:20:35 +01:00
fbd30c388c 2022-11-02 14:19:12 +01:00
ffe364dd97 2022-11-02 14:18:07 +01:00
21236301e0 2022-11-02 14:14:22 +01:00
9d8e95d711 2022-11-02 14:09:27 +01:00
22ef920735 2022-11-02 11:17:13 +01:00
0558fcd9e4 2022-11-02 11:16:22 +01:00
9890800079 2022-11-02 10:27:03 +01:00
d68039f09f 2022-11-02 10:26:30 +01:00
323185d08d 2022-11-02 10:19:05 +01:00
baed8628be 2022-11-02 10:12:59 +01:00
850ccb8179 2022-11-02 10:09:33 +01:00
879adf7b91 2022-10-31 15:48:50 +01:00
123c8fe350 2022-10-31 15:23:19 +01:00
f93a046270 2022-10-31 15:20:21 +01:00
9cc3b41f87 2022-10-31 15:12:38 +01:00
81862f8ee3 2022-10-31 15:07:58 +01:00
3219028980 2022-10-31 15:03:15 +01:00
cf21934931 2022-10-31 14:56:10 +01:00
a7616ad41c 2022-10-31 14:55:39 +01:00
963509fd8a 2022-10-31 14:53:58 +01:00
2c65a75f28 2022-10-31 14:50:11 +01:00
0621d02fff 2022-10-31 14:49:29 +01:00
51b29110bc 2022-10-31 14:48:20 +01:00
8984fcf6af 2022-10-31 14:45:43 +01:00
6c27ad4805 Quick fix for imports 2022-10-31 14:40:28 +01:00
437ccde0f1 2022-10-26 14:56:57 +02:00
e329d2b87f 2022-10-26 14:54:10 +02:00
679d6b78c5 2022-10-26 14:52:20 +02:00
302095a929 2022-10-26 14:50:59 +02:00
8be9656f5d 2022-10-26 14:45:06 +02:00
15fab9c09c 2022-10-26 14:43:48 +02:00
04c8dcc96e 2022-10-26 14:37:03 +02:00
5ddcd8499d 2022-10-26 14:34:57 +02:00
9145085739 2022-10-26 14:32:30 +02:00
ebf356445b 2022-10-26 14:30:18 +02:00
ef5f297a47 2022-10-26 14:30:13 +02:00
7 changed files with 178 additions and 70 deletions

View File

@ -52,6 +52,7 @@ def main():
angle = np.rad2deg(np.arctan(position[0]/position[2])) angle = np.rad2deg(np.arctan(position[0]/position[2]))
drive_distance = np.sqrt(position[0]**2 + position[2]**2) drive_distance = np.sqrt(position[0]**2 + position[2]**2)
print(drive_distance)
if angle < 0: if angle < 0:
arlo.go_diff(POWER, POWER, 0, 1) arlo.go_diff(POWER, POWER, 0, 1)
sleep((abs(angle) * TURN_T)/1000) sleep((abs(angle) * TURN_T)/1000)
@ -61,9 +62,9 @@ def main():
sleep((abs(angle) * TURN_T * CLOCKWISE_OFFSET)/1000) sleep((abs(angle) * TURN_T * CLOCKWISE_OFFSET)/1000)
arlo.stop() arlo.stop()
arlo.go_diff(POWER, POWER + RIGHT_WHEEL_OFFSET, 1, 1) # arlo.go_diff(POWER, POWER + RIGHT_WHEEL_OFFSET, 1, 1)
sleep((drive_distance * DRIVE_T)/1000) # sleep((drive_distance * DRIVE_T)/1000)
arlo.stop() # arlo.stop()
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -5,16 +5,16 @@ import cv2
import robot import robot
LANDMARKS = [7,11,10,6] # SET ARUCO NUMBERS LANDMARKS = [1,2,3,4] # SET ARUCO NUMBERS
POWER = 70 POWER = 70
TURN_T = 7.9 # 1 degree TURN_T = 8.3 # 1 degree
DRIVE_T = 22 # 1 centimeter DRIVE_T = 22 # 1 centimeter
RIGHT_WHEEL_OFFSET = 4 RIGHT_WHEEL_OFFSET = 5
CLOCKWISE_OFFSET = 0.96 CLOCKWISE_OFFSET = 0.8
FOCAL_LENGTH = 1691 FOCAL_LENGTH = 1691
@ -38,21 +38,49 @@ def find_aruco(image):
return {ids[i][0]: box[0] for i, box in enumerate(corners)} return {ids[i][0]: box[0] for i, box in enumerate(corners)}
def careful_forward(drive_time, arlo, careful_range = 600):
def drunk_drive(drive_time, arlo, careful_range = 600):
start = time.time() start = time.time()
end = start + drive_time end = start + drive_time
turning = None turning = None
hit_something = False
while time.time() < end: while time.time() < end:
forward_dist = arlo.read_front_ping_sensor() forward_dist = arlo.read_front_ping_sensor()
right_dist = arlo.read_right_ping_sensor() right_dist = arlo.read_right_ping_sensor()
left_dist = arlo.read_left_ping_sensor() left_dist = arlo.read_left_ping_sensor()
if forward_dist > careful_range and all(x > 400 for x in [right_dist, left_dist]): if forward_dist > careful_range and all(x > 250 for x in [right_dist, left_dist]):
turning = None
arlo.go_diff(POWER, POWER + RIGHT_WHEEL_OFFSET, 1, 1)
else:
if turning == "R" or (forward_dist > careful_range and right_dist > 250 and turning is None):
arlo.go_diff(POWER, POWER, 1, 0)
turning = "R"
else:
arlo.go_diff(POWER, POWER + RIGHT_WHEEL_OFFSET, 0, 1)
turning = "L"
time.sleep(0.01)
def careful_forward(drive_time, arlo, careful_range = 600):
start = time.time()
if drive_time > 0.8:
drive_time = 0.8
hit_something = True
else:
hit_something = False
end = start + drive_time
turning = None
while time.time() < end:
forward_dist = arlo.read_front_ping_sensor()
right_dist = arlo.read_right_ping_sensor()
left_dist = arlo.read_left_ping_sensor()
if forward_dist > careful_range and all(x > 250 for x in [right_dist, left_dist]):
turning = None turning = None
arlo.go_diff(POWER, POWER + RIGHT_WHEEL_OFFSET, 1, 1) arlo.go_diff(POWER, POWER + RIGHT_WHEEL_OFFSET, 1, 1)
else: else:
hit_something = True hit_something = True
if turning == "R" or (forward_dist > careful_range and right_dist > 400 and turning is None): if turning == "R" or (forward_dist > careful_range and right_dist > 250 and turning is None):
arlo.go_diff(POWER, POWER, 1, 0) arlo.go_diff(POWER, POWER, 1, 0)
turning = "R" turning = "R"
else: else:
@ -87,17 +115,15 @@ def main():
if landmark in arucos: if landmark in arucos:
break break
careful_forward(3, noah) drunk_drive(3, noah)
position = cv2.aruco.estimatePoseSingleMarkers( position = cv2.aruco.estimatePoseSingleMarkers(
np.array([arucos[landmark]]), 14.5, CAMERA_MATRIX, DIST_COEF np.array([arucos[landmark]]), 14.5, CAMERA_MATRIX, DIST_COEF
)[1][0][0] )[1][0][0]
angle = np.rad2deg(np.arctan(position[0]/position[2])) angle = np.rad2deg(np.arctan(position[0]/position[2])) - 5
drive_distance = np.sqrt(position[0]**2 + position[2]**2) - 30 drive_distance = np.sqrt(position[0]**2 + position[2]**2) - 100
if drive_distance < 30:
break
if angle < 0: if angle < 0:
noah.go_diff(POWER, POWER, 0, 1) noah.go_diff(POWER, POWER, 0, 1)
@ -109,7 +135,20 @@ def main():
noah.stop() noah.stop()
if not careful_forward((drive_distance * DRIVE_T)/1000, noah, 400): if not careful_forward((drive_distance * DRIVE_T)/1000, noah, 400):
break arucos = find_aruco(noah.take_photo())
if landmark in arucos:
position = cv2.aruco.estimatePoseSingleMarkers(
np.array([arucos[landmark]]), 14.5, CAMERA_MATRIX, DIST_COEF
)[1][0][0]
drive_distance = np.sqrt(position[0]**2 + position[2]**2) - 25
noah.go_diff(POWER, POWER, 1, 1)
time.sleep((drive_distance * DRIVE_T)/1000)
noah.stop()
break
if __name__ == "__main__": if __name__ == "__main__":
start = time.time()
main() main()
print(f"Drove for {time.time() - start} seconds")

BIN
rally.zip Normal file

Binary file not shown.

161
rally2.py
View File

@ -7,18 +7,18 @@ from selflocalization import particle, camera
import robot import robot
LANDMARKS = [7, 11, 10, 6] LANDMARKS = [6,8,9,7]
LANDMARK_POSITIONS = { LANDMARK_POSITIONS = {
7: [0, 0], 6: [0, 0],
11: [200, 0], 8: [300, 0],
10: [0, 300], 9: [0, 400],
6: [200, 300] 7: [300, 400]
} }
POWER = 70 POWER = 70
TURN_T = 9.1 # 1 degree TURN_T = 9.6 # 1 degree
DRIVE_T = 22 # 1 centimeter DRIVE_T = 22 # 1 centimeter
RIGHT_WHEEL_OFFSET = 4 RIGHT_WHEEL_OFFSET = 4
@ -41,45 +41,47 @@ NUM_PARTICLES = 1000
def look_around(noah, particles, cam, est_pose): def look_around(noah, particles, cam, est_pose):
for _ in range(24): for _ in range(24):
time.sleep(0.2)
# Fetch next frame # Fetch next frame
colour = cam.get_next_frame() for _ in range(10):
landmark_values = [] colour = cam.get_next_frame()
landmark_values = []
# Detect objects # Detect objects
objectIDs, dists, angles = cam.detect_aruco_objects(colour) objectIDs, dists, angles = cam.detect_aruco_objects(colour)
if not isinstance(objectIDs, type(None)): if not isinstance(objectIDs, type(None)):
# List detected objects # List detected objects
for i in range(len(objectIDs)): for i in range(len(objectIDs)):
print( print(
"Object ID = ", objectIDs[i], ", Distance = ", dists[i], ", angle = ", angles[i]) "Object ID = ", objectIDs[i], ", Distance = ", dists[i], ", angle = ", angles[i])
if objectIDs[i] in LANDMARKS: if objectIDs[i] in LANDMARKS:
landmark_values.append((objectIDs[i], dists[i], angles[i])) landmark_values.append((objectIDs[i], dists[i] + 22.5, angles[i]))
# Compute particle weights # Compute particle weights
for p in particles: for p in particles:
calc_weight(p, landmark_values) calc_weight(p, landmark_values)
# Resampling # Resampling
particles = particle.resample(particles) particles = particle.resample(particles)
# Draw detected objects # Draw detected objects
cam.draw_aruco_objects(colour) cam.draw_aruco_objects(colour)
else: else:
# No observation - reset weights to uniform distribution # No observation - reset weights to uniform distribution
for p in particles: for p in particles:
p.setWeight(1.0/NUM_PARTICLES) p.setWeight(1.0/NUM_PARTICLES)
particle.add_uncertainty(particles, SIGMA, SIGMA_THETA) particle.add_uncertainty(particles, SIGMA, SIGMA_THETA)
# The estimate of the robots current pose # The estimate of the robots current pose
est_pose = particle.estimate_pose(particles) est_pose = particle.estimate_pose(particles)
calc_weight(est_pose, landmark_values) calc_weight(est_pose, landmark_values)
noah.go_diff(POWER, POWER, 0, 1) noah.go_diff(POWER, POWER, 0, 1)
time.sleep((15 * TURN_T)/1000) time.sleep((15 * TURN_T)/1000)
noah.stop() noah.stop()
for p in particles: for p in particles:
p.setTheta(p.theta + np.deg2rad(15)) p.setTheta(p.theta - np.deg2rad(15))
# The estimate of the robots current pose # The estimate of the robots current pose
est_pose = particle.estimate_pose(particles) est_pose = particle.estimate_pose(particles)
@ -95,7 +97,7 @@ def turn_towards_landmark(noah, particles, est_pose, landmark):
angle = np.rad2deg(np.arctan(relative_pos[1]/relative_pos[0])) angle = np.rad2deg(np.arctan(relative_pos[1]/relative_pos[0]))
turn_angle = np.mod(angle - (np.rad2deg(current_theta) - 180), 360) turn_angle = np.mod(angle - (np.rad2deg(current_theta) - 180), 360)
for p in particles: for p in particles:
p.setTheta(p.theta + np.deg2rad(turn_angle)) p.setTheta(p.theta - np.deg2rad(turn_angle))
if turn_angle < 180: if turn_angle < 180:
noah.go_diff(POWER, POWER, 0, 1) noah.go_diff(POWER, POWER, 0, 1)
time.sleep((abs(turn_angle) * TURN_T)/1000) time.sleep((abs(turn_angle) * TURN_T)/1000)
@ -105,6 +107,7 @@ def turn_towards_landmark(noah, particles, est_pose, landmark):
time.sleep((abs(360 - turn_angle) * TURN_T * CLOCKWISE_OFFSET)/1000) time.sleep((abs(360 - turn_angle) * TURN_T * CLOCKWISE_OFFSET)/1000)
noah.stop() noah.stop()
particle.add_uncertainty(particles, SIGMA, SIGMA_THETA)
# The estimate of the robots current pose # The estimate of the robots current pose
est_pose = particle.estimate_pose(particles) est_pose = particle.estimate_pose(particles)
return particles, est_pose return particles, est_pose
@ -120,7 +123,7 @@ def time_to_landmark(est_pose, landmark):
return (DRIVE_T * drive_distance)/1000 return (DRIVE_T * drive_distance)/1000
def drive_until_stopped(noah): def drive_until_stopped(noah, particles):
noah.go_diff(POWER, POWER+RIGHT_WHEEL_OFFSET, 1, 1) noah.go_diff(POWER, POWER+RIGHT_WHEEL_OFFSET, 1, 1)
start = time.time() start = time.time()
while True: while True:
@ -136,10 +139,24 @@ def drive_until_stopped(noah):
if right_dist < 400: if right_dist < 400:
noah.stop() noah.stop()
break break
if time.time() - start > 5:
noah.stop()
break
time.sleep(0.01) time.sleep(0.01)
end = time.time() end = time.time()
return end - start time_driven = end - start
distance_driven = (time_driven*1000)/DRIVE_T
for p in particles:
x = np.cos(p.theta) * distance_driven
y = np.sin(p.theta) * distance_driven
p.x = p.x + x
p.y = p.y + y
particle.add_uncertainty(particles, SIGMA, SIGMA_THETA)
est_pose = particle.estimate_pose(particles)
return time_driven, est_pose, particles
def drunk_drive(noah): def drunk_drive(noah):
@ -164,7 +181,8 @@ def drunk_drive(noah):
time.sleep(0.01) time.sleep(0.01)
def inch_closer(noah): def inch_closer(noah, particles):
start = time.time()
noah.go_diff(POWER, POWER+RIGHT_WHEEL_OFFSET, 1, 1) noah.go_diff(POWER, POWER+RIGHT_WHEEL_OFFSET, 1, 1)
while True: while True:
forward_dist = noah.read_front_ping_sensor() forward_dist = noah.read_front_ping_sensor()
@ -172,6 +190,19 @@ def inch_closer(noah):
noah.stop() noah.stop()
break break
end = time.time()
time_driven = end - start
distance_driven = (time_driven*1000)/DRIVE_T
for p in particles:
x = np.cos(p.theta) * distance_driven
y = np.sin(p.theta) * distance_driven
p.x = p.x + x
p.y = p.y + y
particle.add_uncertainty(particles, SIGMA, SIGMA_THETA)
est_pose = particle.estimate_pose(particles)
return est_pose, particles
def initialize_particles(num_particles): def initialize_particles(num_particles):
particles = [] particles = []
@ -217,33 +248,67 @@ def calc_weight(particle, landmark_values):
particle.setWeight(np.product(weights)) particle.setWeight(np.product(weights))
def turn_90_degrees(noah, est_pose, particles):
x_values = [i[0] for i in LANDMARK_POSITIONS.values()]
y_values = [i[1] for i in LANDMARK_POSITIONS.values()]
middle = np.array([max(x_values)/2, max(y_values)/2])
def main(): current_position = np.array([est_pose.x, est_pose.y])
relative_pos = middle - current_position
angle = np.arctan(relative_pos[1]/relative_pos[0])
relative_angle = np.mod(angle - est_pose.theta, 2.0*np.pi)
clockwise = relative_angle > 180
if clockwise:
noah.go_diff(POWER, POWER, 1, 0)
time.sleep((90 * TURN_T * CLOCKWISE_OFFSET)/1000)
else:
noah.go_diff(POWER, POWER, 0, 1)
time.sleep((90 * TURN_T)/1000)
noah.stop()
for p in particles:
if clockwise:
p.setTheta(p.theta - np.deg2rad(90))
else:
p.setTheta(p.theta + np.deg2rad(90))
particle.add_uncertainty(particles, SIGMA, SIGMA_THETA)
_, est_pose, particles = drive_until_stopped(noah, particles)
return est_pose, particles
def main(noah):
landmark_order = LANDMARKS + [ landmark_order = LANDMARKS + [
LANDMARKS[0] LANDMARKS[0]
] ]
cam = camera.Camera(0, 'arlo', useCaptureThread=True)
particles = initialize_particles(NUM_PARTICLES) particles = initialize_particles(NUM_PARTICLES)
# The estimate of the robots current pose # The estimate of the robots current pose
est_pose = particle.estimate_pose(particles) est_pose = particle.estimate_pose(particles)
noah = robot.Robot() # Noah er vores robots navn
cam = camera.Camera(0, 'arlo', useCaptureThread=True)
for landmark in landmark_order: for landmark in landmark_order:
print(f"Going to landmark {landmark}") print(f"Going to landmark {landmark}")
while True: while True:
particles, est_pose = look_around(noah, particles, cam, est_pose) particles, est_pose = look_around(noah, particles, cam, est_pose)
particles, est_pose = turn_towards_landmark( print(est_pose)
noah, particles, est_pose, landmark) particles, est_pose = turn_towards_landmark(noah, particles, est_pose, landmark)
drive_time = time_to_landmark(est_pose, landmark) drive_time = time_to_landmark(est_pose, landmark)
if not abs(drive_until_stopped(noah) - drive_time) < 0.5: time_driven, est_pose, particles = drive_until_stopped(noah, particles)
drunk_drive(noah) if not abs(time_driven - drive_time) < 0.5:
# drunk_drive(noah)
est_pose, particles = turn_90_degrees(noah, est_pose, particles)
continue continue
inch_closer(noah)
est_pose, particles = inch_closer(noah, particles)
break break
if __name__ == "__main__": if __name__ == "__main__":
main() noah = robot.Robot() # Noah er vores robots navn
try:
main(noah)
except KeyboardInterrupt:
noah.stop()

View File

@ -1,2 +1 @@
from .robot import Robot from .robot import Robot
from .arlo import Arlo

View File

@ -100,7 +100,7 @@ class CaptureThread(threading.Thread):
class Camera(object): class Camera(object):
"""This class is responsible for doing the image processing. It detects known landmarks and """This class is responsible for doing the image processing. It detects known landmarks and
measures distances and orientations to these.""" measures distances and orientations to these."""
def __init__(self, camidx, robottype='arlo', useCaptureThread=False): def __init__(self, camidx, robottype='arlo', useCaptureThread=False):
@ -114,13 +114,14 @@ class Camera(object):
# Set camera calibration info # Set camera calibration info
if robottype == 'arlo': if robottype == 'arlo':
self.imageSize = (1280, 720) focal_length = 1050
self.imageSize = (1024, 720)
#self.intrinsic_matrix = np.asarray([ 7.1305391967046853e+02, 0., 3.1172820723774367e+02, 0., #self.intrinsic_matrix = np.asarray([ 7.1305391967046853e+02, 0., 3.1172820723774367e+02, 0.,
# 7.0564929862291285e+02, 2.5634470978315028e+02, 0., 0., 1. ], dtype = np.float64) # 7.0564929862291285e+02, 2.5634470978315028e+02, 0., 0., 1. ], dtype = np.float64)
#self.intrinsic_matrix = np.asarray([ 6.0727040957659040e+02, 0., 3.0757300398967601e+02, 0., #self.intrinsic_matrix = np.asarray([ 6.0727040957659040e+02, 0., 3.0757300398967601e+02, 0.,
# 6.0768864690145904e+02, 2.8935674612358201e+02, 0., 0., 1. ], dtype = np.float64) # 6.0768864690145904e+02, 2.8935674612358201e+02, 0., 0., 1. ], dtype = np.float64)
self.intrinsic_matrix = np.asarray([500, 0., self.imageSize[0] / 2.0, 0., self.intrinsic_matrix = np.asarray([focal_length, 0., self.imageSize[0] / 2.0, 0.,
500, self.imageSize[1] / 2.0, 0., 0., 1.], dtype = np.float64) focal_length, self.imageSize[1] / 2.0, 0., 0., 1.], dtype = np.float64)
self.intrinsic_matrix.shape = (3, 3) self.intrinsic_matrix.shape = (3, 3)
#self.distortion_coeffs = np.asarray([ 1.1911006165076067e-01, -1.0003366233413549e+00, #self.distortion_coeffs = np.asarray([ 1.1911006165076067e-01, -1.0003366233413549e+00,
# 1.9287903277399834e-02, -2.3728201444308114e-03, -2.8137265581326476e-01 ], dtype = np.float64) # 1.9287903277399834e-02, -2.3728201444308114e-03, -2.8137265581326476e-01 ], dtype = np.float64)

View File

@ -37,6 +37,9 @@ class Particle(object):
def copy(self): def copy(self):
return Particle(self.x, self.y, self.theta, self.weight) return Particle(self.x, self.y, self.theta, self.weight)
def __str__(self) -> str:
return f"({self.x},{self.y},{self.theta})"
def estimate_pose(particles_list): def estimate_pose(particles_list):
"""Estimate the pose from particles by computing the average position and orientation over all particles. """Estimate the pose from particles by computing the average position and orientation over all particles.