def update_with_accel(self,
                       delta_t):  # update with calculated acceleration
     # update position, velocity, and orientation
     vel_new = self.vel + self.accel_t * delta_t
     # ori_delta is the change in orientation, counter-clockwise is positive
     if self.vel == 0:  # no change in orientation if no speed
         ori_delta = 0
     else:
         # velocity is signed; should not reset this radian angle ori_delta
         ori_delta = self.accel_r * delta_t / self.vel
     # should avoid overshooting of rotating angle, choosing smaller one
     if self.accel_r > 0:
         if self.vel > 0:
             ori_delta = min(ori_delta, reset_radian(self.accel_ori))
         elif self.vel < 0:
             ori_delta = max(ori_delta, reset_radian(self.accel_ori - pi))
     elif self.accel_r < 0:
         if self.vel > 0:
             ori_delta = max(ori_delta, reset_radian(self.accel_ori))
         elif self.vel < 0:
             ori_delta = min(ori_delta, reset_radian(self.accel_ori + pi))
     ori_new = reset_radian(self.ori + ori_delta)
     # use middle value of velocity and orientation to calculation next position
     vel_mid = (vel_new + self.vel) / 2
     ori_mid = (ori_new + self.ori) / 2
     # update position
     self.pos[0] = self.pos[0] + cos(ori_mid) * vel_mid * delta_t
     self.pos[1] = self.pos[1] + sin(ori_mid) * vel_mid * delta_t
     # update the new velocity and orientation
     self.vel = vel_new
     self.ori = ori_new
 def update_with_accel(self, accel_r, delta_t):
     # update position and orientation of automaton with acceleration
     # accel_r is signed centripetal acceleration, rotating ccw is positive
     ori_delta = accel_r * delta_t / self.vel
     # print warning msg if rotation angle is too large
     if ori_delta > pi / 2:
         print("rotation angle is too large for one update")
     # use middle orientation to calculate new position
     ori_mid = reset_radian(self.ori + ori_delta / 2)
     self.pos[0] = self.pos[0] + cos(ori_mid) * self.vel * delta_t
     self.pos[1] = self.pos[1] + sin(ori_mid) * self.vel * delta_t
     # update orientation
     self.ori = reset_radian(self.ori + ori_delta)
 def check_neighbor(self, pos):
     # input position of the automaton to be compared with
     # accumulate changes on the feedback vector
     dist_temp = hypot(pos[0] - self.pos[0], pos[1] - self.pos[1])
     if dist_temp < self.radius:  # input automaton inside sensing circle
         if (not self.neighbor_detected):
             self.neighbor_detected = True  # set detection flag
         # 1.calculate feedback based on distance
         # proportional to how close the neighbor to the automaton
         fb_magnitude = (self.radius - dist_temp) * self.fb_mag_coef
         # 2.also change magnitude of feedback according to beta
         # theta_fb is the absolute direction of feedback vector
         theta_fb = atan2(pos[1] - self.pos[1], pos[0] - self.pos[0])
         # beta is angle of feedback vector to positive dividing direction
         beta = reset_radian(theta_fb - self.ori + self.alpha)
         # beta_coef is to be applied to fb_magnitude, in [-1, 1]
         # (0, pi/2) pulling sector
         # (pi/2, pi) pushing sector
         # (pi, 3*pi/2) pulling sector
         # (3*pi/2, 2*pi) pushing sector
         beta_coef = sin(beta * 2)  # it happens to be a sin() function
         # apply beta_coef to the feedback magnetitude, make it signed
         fb_magnitude = fb_magnitude * beta_coef
         # 3.add feedback as acceleration from input automaton
         self.fb_vector[
             0] = self.fb_vector[0] + cos(theta_fb) * fb_magnitude
         self.fb_vector[
             1] = self.fb_vector[1] + sin(theta_fb) * fb_magnitude
 def check_boundary(self,
                    arena_size):  # rebound the automaton on boundaries
     if self.vel == 0: return  # nothing to do if automaton is still
     # use velocities in Cartesian arena coordinates to control automaton rebound
     vel_x_temp = self.vel * cos(self.ori)
     vel_y_temp = self.vel * sin(self.ori)
     if (self.pos[0] >= arena_size[0]/2 and vel_x_temp > 0) \
         or (self.pos[0] <= -arena_size[0]/2 and vel_x_temp < 0):
         # if automaton out of left or right bouddaries
         # flip positive moving direction along vertical line
         self.ori = reset_radian(2 * (pi / 2) - self.ori)
     if (self.pos[1] >= arena_size[1]/2 and vel_y_temp > 0) \
         or (self.pos[1] <= -arena_size[1]/2 and vel_y_temp < 0):
         # if automaton out of top or bottom bouddaries
         # flip positive moving direction along horizontal line
         self.ori = reset_radian(2 * (0) - self.ori)
Exemple #5
0
 def check_neighbor(self, pos):
     # input position of the automaton to be compared with
     # accumulate changes on the feedback vector
     dist_temp = hypot(pos[0] - self.pos[0], pos[1] - self.pos[1])
     if dist_temp < self.radius:  # input automaton inside sensing circle
         if (not self.neighbor_detected):
             self.neighbor_detected = True  # set detection flag
         # 1.calculate feedback based on distance
         # proportional to how close the neighbor to the automaton
         fb_magnitude = (self.radius - dist_temp) * self.fb_mag_coef
         # 2.furthur change magnitude of feedback according to beta
         # theta_fb is absolute direction of feedback vector
         theta_fb = atan2(pos[1] - self.pos[1], pos[0] - self.pos[0])
         # beta is angle of feedback vector to positive dividing direction
         beta = reset_radian(theta_fb - self.ori + self.alpha)
         # beta_coef is to be applied to fb_magnitude
         # the more perpendicular the beta, the stronger the feedback
         # the sign of beta means pull or push effect, will impart to fb_magnitude
         # beta_coef in [-1, 1]
         beta_coef = sin(beta)
         # apply beta_coef to the feedback magnetitude, make it signed
         fb_magnitude = fb_magnitude * beta_coef
         # 3.add feedback as acceleration from input automaton
         self.fb_vector[
             0] = self.fb_vector[0] + cos(theta_fb) * fb_magnitude
         self.fb_vector[
             1] = self.fb_vector[1] + sin(theta_fb) * fb_magnitude
 def calculate_accel(self):
     # calculate both tangential and centripetal acceleration
     # based on accumulated feedback vector from all in-range neighbors
     accel_magnitude = hypot(self.fb_vector[0], self.fb_vector[1])
     # relative orientation to the positive moving direction
     self.accel_ori = reset_radian(
         atan2(self.fb_vector[1], self.fb_vector[0]) - self.ori)
     # tangiential and centripetal acceleration
     self.accel_t = accel_magnitude * cos(self.accel_ori)
     self.accel_r = accel_magnitude * sin(self.accel_ori)