def update_vel(self, delta_time, desired_vel): ang = signed_angle(self.dir, desired_vel) if abs(ang) < MIN_ROTATION_ANGLE: ang = 0.0 ang = ROTATION_GAIN * ang abs_vel = min(length(desired_vel), self.max_vel) # don't move forward when doing a sharp turn; # this seems sensible and also prevents bots from # slamming into obstacles when trying to move away # # !this only makes sense with ROTATION_GAIN = 1.0! abs_vel *= cos(signed_angle(desired_vel, self.dir)) if abs_vel < 0: abs_vel = 0 # these are the velocities wheels would get # if they didn't have to accelerate smoothly target_lvel = abs_vel - 0.5 * self.width * ang target_rvel = abs_vel + 0.5 * self.width * ang #self.lvel = target_lvel #self.rvel = target_rvel if abs(self.lvel - target_lvel) < delta_time * BOT_ACCEL_CAP: self.lvel = target_lvel else: self.lvel += copysign(BOT_ACCEL_CAP, target_lvel - self.lvel) * delta_time if abs(self.rvel - target_rvel) < delta_time * BOT_ACCEL_CAP: self.rvel = target_rvel else: self.rvel += copysign(BOT_ACCEL_CAP, target_rvel - self.rvel) * delta_time # cap velocity v = max(self.lvel, self.rvel) if v > self.max_vel: self.lvel *= self.max_vel / v self.rvel *= self.max_vel / v
def draw(self, screen, field): if graphics.DRAW_SENSOR_RAYS: if ROTATE_SENSORS: ang = self.get_heading_angle() else: ang = 0.0 for s, d in zip(self.sensors, self.distances): r = s.get_ray(self.pos, ang) graphics.draw_line(screen, field, (115, 115, 200), r.orig, r.orig + r.dir * d, 1) if COLLISION_CHECK and self.collision: # draw small purple circle indicating collision state graphics.draw_circle(screen, field, (255, 0, 255), self.pos, 0.5 * BOT_RADIUS) # draw projections of virtual velocity onto sensor rays if graphics.DRAW_SENSOR_RAYS: vel_ang = signed_angle(self.virtual_vel_before_check, Vector(0.0, 1.0)) abs_vel = length(self.virtual_vel_before_check) if ROTATE_SENSORS: ang = self.get_heading_angle() else: ang = 0.0 for s in self.sensors: r = s.get_ray(self.pos, ang) c = cos(signed_angle(self.virtual_vel_before_check, r.dir)) proj = c * abs_vel; if proj < 0: continue graphics.draw_line(screen, field, (115, 200, 200), r.orig, r.orig + r.dir * proj, 2) v = Vector(0.0, 0.0) try: v = 0.5 * normalize(self.virtual_vel_before_check) except ZeroDivisionError: pass # draw virtual velocity vector that was picked before collision check graphics.draw_line(screen, field, (0, 200, 0), self.pos, self.pos + v, 1)
def testAngle(self): from math import pi self.assertAlmostEqual(signed_angle(Vector(1.0, 0.0), Vector(0.0, 1.0)), pi / 2) self.assertAlmostEqual(angle(Vector(1.0, 0.0), Vector(0.0, 1.0)), pi / 2) self.assertAlmostEqual(signed_angle(Vector(-1.0, 1.0), Vector(1.0, 1.0)), -pi / 2) self.assertAlmostEqual(angle(Vector(-1.0, 1.0), Vector(1.0, 1.0)), pi / 2) self.assertAlmostEqual(signed_angle(Vector(1.0, 0.0), Vector(100.0, 100.0)), pi / 4) self.assertAlmostEqual(angle(Vector(1.0, 0.0), Vector(100.0, 100.0)), pi / 4) self.assertAlmostEqual(abs(signed_angle(Vector(-100.0, 0.0), Vector(0.01, 0.0))), pi) self.assertAlmostEqual(angle(Vector(-100.0, 0.0), Vector(0.01, 0.0)), pi)
def testAngle(self): from math import pi self.assertAlmostEqual( signed_angle(Vector(1.0, 0.0), Vector(0.0, 1.0)), pi / 2) self.assertAlmostEqual(angle(Vector(1.0, 0.0), Vector(0.0, 1.0)), pi / 2) self.assertAlmostEqual( signed_angle(Vector(-1.0, 1.0), Vector(1.0, 1.0)), -pi / 2) self.assertAlmostEqual(angle(Vector(-1.0, 1.0), Vector(1.0, 1.0)), pi / 2) self.assertAlmostEqual( signed_angle(Vector(1.0, 0.0), Vector(100.0, 100.0)), pi / 4) self.assertAlmostEqual(angle(Vector(1.0, 0.0), Vector(100.0, 100.0)), pi / 4) self.assertAlmostEqual( abs(signed_angle(Vector(-100.0, 0.0), Vector(0.01, 0.0))), pi) self.assertAlmostEqual(angle(Vector(-100.0, 0.0), Vector(0.01, 0.0)), pi)
def draw(self, screen, field): if graphics.DRAW_SENSOR_RAYS: if ROTATE_SENSORS: ang = self.get_heading_angle() else: ang = 0.0 for s, d in zip(self.sensors, self.distances): r = s.get_ray(self.pos, ang) graphics.draw_line(screen, field, (115, 115, 200), r.orig, r.orig + r.dir * d, 1) if COLLISION_CHECK and self.collision: # draw small purple circle indicating collision state graphics.draw_circle(screen, field, (255, 0, 255), self.pos, 0.5 * BOT_RADIUS) # draw projections of virtual velocity onto sensor rays if graphics.DRAW_SENSOR_RAYS: vel_ang = signed_angle(self.virtual_vel_before_check, Vector(0.0, 1.0)) abs_vel = length(self.virtual_vel_before_check) if ROTATE_SENSORS: ang = self.get_heading_angle() else: ang = 0.0 for s in self.sensors: r = s.get_ray(self.pos, ang) c = cos(signed_angle(self.virtual_vel_before_check, r.dir)) proj = c * abs_vel if proj < 0: continue graphics.draw_line(screen, field, (115, 200, 200), r.orig, r.orig + r.dir * proj, 2) v = Vector(0.0, 0.0) try: v = 0.5 * normalize(self.virtual_vel_before_check) except ZeroDivisionError: pass # draw virtual velocity vector that was picked before collision check graphics.draw_line(screen, field, (0, 200, 0), self.pos, self.pos + v, 1)
def draw(self, screen, field): draw_circle(screen, field, BOT_COLOR, self.pos, self.radius, 1) top_angle = 40 * pi / 180 x = self.radius * sin(top_angle) y = self.radius * cos(top_angle) ang = signed_angle(Vector(0.0, 1.0), self.dir) pa = self.pos + rotate(Vector(-x, -y), ang) pb = self.pos + rotate(Vector( x, -y), ang) pc = self.pos + rotate(Vector(0.0, self.radius), ang) draw_line(screen, field, BOT_COLOR, pa, pb, 1) draw_line(screen, field, BOT_COLOR, pa, pc, 1) draw_line(screen, field, BOT_COLOR, pb, pc, 1)
def calc_desired_velocity(self, bots, obstacles, targets): vel = self.real_vel self.collision_delta_time = length(vel) / BOT_ACCEL_CAP if self.movement != Movement.Accel: vel = Vector(0, 0) for inter in bots: if (not KNOW_BOT_POSITIONS) and dist(inter.real.pos, self.pos) > self.max_sensing_distance: continue force = -potential.gradient(potential.morse(r0=2 * BOT_RADIUS, k=2.5, a=4.0), dist(inter.real.pos, self.pos), self.pos - inter.real.pos, self.radius + inter.virtual.radius) vel += _FORCE_SENSITIVITY * force for target in targets: force = -potential.gradient(potential.linear(k=-10.0), dist(target, self.pos), target - self.pos, 0) vel += _FORCE_SENSITIVITY * force if ROTATE_SENSORS: ang = self.get_heading_angle() else: ang = 0.0 self.distances = [] for s in self.sensors: d = s.get_distance(self.pos, ang, obstacles) self.distances.append(d) if d < self.max_sensing_distance: force = -potential.gradient(potential.inverse_quadratic(k=1.5), d, -s.get_ray(self.pos, ang).dir, OBSTACLE_CLEARANCE) vel += _FORCE_SENSITIVITY * force * self.obstacle_force_coeff if self.movement == Movement.Dir: if length(vel) > 0: vel = normalize(vel) # TODO: get max_vel from corresponding Model if length(vel) > BOT_VEL_CAP: vel = normalize(vel) * BOT_VEL_CAP self.virtual_vel_before_check = vel if COLLISION_CHECK: # check for possible collisions: # stop moving forward if an obstacle is nearby collision = False abs_vel = length(vel) if ROTATE_SENSORS: ang = self.get_heading_angle() else: ang = 0.0 for cur_d, s in zip(self.distances, self.sensors): if cur_d == s.max_distance: continue r = s.get_ray(self.pos, ang) c = cos(signed_angle(vel, r.dir)) new_d = cur_d - c * abs_vel * self.collision_delta_time if new_d < CRITICAL_DIST and new_d < cur_d: collision = True break if not collision: # separate check for possible collision with another bot for inter in bots: # don't count collsions with self if inter.virtual is self: continue new_d = dist(inter.real.pos + self.collision_delta_time * inter.real.vel, self.pos + self.collision_delta_time * vel) new_d -= (self.radius + inter.real.radius) cur_d = dist(inter.real.pos, self.pos) cur_d -= (self.radius + inter.real.radius) if d <= CRITICAL_DIST and new_d < cur_d: collision = True break if collision: vel = normalize(vel) * CRITICAL_VEL self.collision = True else: self.collision = False return vel
def calc_desired_velocity(self, bots, obstacles, targets): vel = self.real_vel self.collision_delta_time = length(vel) / BOT_ACCEL_CAP if self.movement != Movement.Accel: vel = Vector(0, 0) for inter in bots: if (not KNOW_BOT_POSITIONS) and dist( inter.real.pos, self.pos) > self.max_sensing_distance: continue force = -potential.gradient( potential.morse(r0=2 * BOT_RADIUS, k=2.5, a=4.0), dist(inter.real.pos, self.pos), self.pos - inter.real.pos, self.radius + inter.virtual.radius) vel += _FORCE_SENSITIVITY * force for target in targets: force = -potential.gradient(potential.linear( k=-10.0), dist(target, self.pos), target - self.pos, 0) vel += _FORCE_SENSITIVITY * force if ROTATE_SENSORS: ang = self.get_heading_angle() else: ang = 0.0 self.distances = [] for s in self.sensors: d = s.get_distance(self.pos, ang, obstacles) self.distances.append(d) if d < self.max_sensing_distance: force = -potential.gradient(potential.inverse_quadratic(k=1.5), d, -s.get_ray(self.pos, ang).dir, OBSTACLE_CLEARANCE) vel += _FORCE_SENSITIVITY * force * self.obstacle_force_coeff if self.movement == Movement.Dir: if length(vel) > 0: vel = normalize(vel) # TODO: get max_vel from corresponding Model if length(vel) > BOT_VEL_CAP: vel = normalize(vel) * BOT_VEL_CAP self.virtual_vel_before_check = vel if COLLISION_CHECK: # check for possible collisions: # stop moving forward if an obstacle is nearby collision = False abs_vel = length(vel) if ROTATE_SENSORS: ang = self.get_heading_angle() else: ang = 0.0 for cur_d, s in zip(self.distances, self.sensors): if cur_d == s.max_distance: continue r = s.get_ray(self.pos, ang) c = cos(signed_angle(vel, r.dir)) new_d = cur_d - c * abs_vel * self.collision_delta_time if new_d < CRITICAL_DIST and new_d < cur_d: collision = True break if not collision: # separate check for possible collision with another bot for inter in bots: # don't count collsions with self if inter.virtual is self: continue new_d = dist( inter.real.pos + self.collision_delta_time * inter.real.vel, self.pos + self.collision_delta_time * vel) new_d -= (self.radius + inter.real.radius) cur_d = dist(inter.real.pos, self.pos) cur_d -= (self.radius + inter.real.radius) if d <= CRITICAL_DIST and new_d < cur_d: collision = True break if collision: vel = normalize(vel) * CRITICAL_VEL self.collision = True else: self.collision = False return vel