当前位置:   article > 正文

多智能体系统编队算法仿真--python3实现_匀布算法

匀布算法

初始条件

  1. 智能体位置随机生成
  2. 所有智能体位置全局可知
  3. 目标多边形位置给定
  4. 所有个体运行相同算法,根据环境来决定自己动作。

目标:形成均匀多边形分布,所谓的  ‘均匀’ 效果如下图:即是多边形上间距相等


问题拆分

  1. 抵达均匀多边形
  2. 均匀化分布

1 .抵达均匀多边形:

  1. '''code = 'utf-8'''
  2. '''author = peng'''
  3. import copy
  4. import numpy as np
  5. import matplotlib.pyplot as plt
  6. from matplotlib import animation
  7. import time
  8. NUM = 10 #设置无人机数量
  9. MOVE_DISTANCE = 0.3
  10. JianCeError = 0.1
  11. '''根据无人机数量NUM得出边界最大容量数量 : MAXNUM'''
  12. if ((NUM - 4)/4)%1==0:
  13. MAXNUM = (NUM - 4)/4
  14. else:MAXNUM = int((NUM - 4)/4) +1
  15. '''JIANJU是调整单位距离'''
  16. JIANJU = 50 /(MAXNUM+1)
  17. x = np.random.randint(1, 100, NUM)
  18. y = np.random.randint(1, 100, NUM)
  19. # x = [36,37,38,39]
  20. # y = [36,37,38,39]
  21. Point_list = []
  22. for i in range(NUM):
  23. Point_list.append([x[i], y[i]])
  24. DING_LIST = [[25, 25], [75, 25], [75, 75], [25, 75]]
  25. DingX, DingY = [], []
  26. for each in DING_LIST:
  27. DingX.append(each[0])
  28. DingY.append(each[1])
  29. DingX.append(DING_LIST[0][0])
  30. DingY.append(DING_LIST[0][1])
  31. fig, ax = plt.subplots()
  32. ax.set_xlim(0, 100)
  33. ax.set_ylim(0, 100)
  34. sc = ax.scatter(x, y, color='r', alpha=0.7,marker='1',linewidth = 10)
  35. ax.plot(DingX, DingY, color = 'black',linestyle = ':')
  36. class Point():
  37. MOVE_DISTANCE = MOVE_DISTANCE
  38. JianCeError = JianCeError
  39. MAXNUM = MAXNUM
  40. JIANJU = JIANJU
  41. tiaozheng_aim = None
  42. def __init__(self,id):
  43. self.id = id
  44. def decide(self,list = copy.deepcopy(DING_LIST)):
  45. if self.tiaozheng_aim == None: #调整目标定下来就不需要改变了
  46. nearest = self.detect_nearest(list) #检测最近顶点
  47. ID = self.occupy(nearest) #检测占领者
  48. if ID == self.id :
  49. self.update(nearest)
  50. pass #自己占领
  51. elif ID == None:self.update(nearest) #无人占领,往该方向移动
  52. else:# self.update([50,50])
  53. self.tiaozheng_aim = self.adjust(ID) #调整目标
  54. if self.tiaozheng_aim: #调整成功
  55. self.update(self.tiaozheng_aim)
  56. else: #调整失败
  57. # print(list)
  58. list2 = copy.deepcopy(list) #深复制防出错
  59. list2.remove(nearest)
  60. # print(list)
  61. return self.decide(list2)
  62. else:self.update(self.tiaozheng_aim) #有调整目标,直接移往该方向
  63. def adjust(self,ID):
  64. order = obj_list[ID].send() #1,0
  65. if order == None:return None
  66. for each in DING_LIST:
  67. d = self.distance_calculate(each, Point_list[ID])
  68. if d < self.JianCeError:
  69. identity = DING_LIST.index(each)
  70. aim = copy.deepcopy(DING_LIST[identity])
  71. count = self.MAXNUM - order #1,2
  72. if count % 2 == 0: # 偶数顺时针
  73. if identity == 3:
  74. aim[0] += self.JIANJU * (count / 2)
  75. return aim
  76. elif identity == 2:
  77. aim[1] -= self.JIANJU * (count / 2)
  78. return aim
  79. elif identity == 1:
  80. aim[0] -= self.JIANJU * (count / 2)
  81. return aim
  82. else:
  83. aim[1] += self.JIANJU * (count / 2)
  84. return aim
  85. elif identity == 3: # 奇数逆时针
  86. aim[1] -= self.JIANJU * (int((count / 2))+1)
  87. return aim
  88. elif identity == 2:
  89. aim[0] -= self.JIANJU * (int((count / 2))+1)
  90. return aim
  91. elif identity == 1:
  92. aim[1] += self.JIANJU * (int((count / 2))+1)
  93. return aim
  94. else:
  95. aim[0] += self.JIANJU * (int((count / 2))+1)
  96. return aim
  97. def detect_nearest(self,list):
  98. init_distance = self.distance_calculate(Point_list[self.id], list[0])
  99. count, i = 0, 0
  100. for each in list:
  101. D = self.distance_calculate(Point_list[self.id], each)
  102. if D < init_distance:
  103. init_distance = D
  104. count = i
  105. i += 1
  106. return list[count]
  107. def distance_calculate(self, A, B): # [1,1],[2,2] 得1.4142135623730951
  108. return pow(pow(abs(A[0] - B[0]), 2) + pow(abs(A[1] - B[1]), 2), 0.5)
  109. def update(self,aim):
  110. self_pot = copy.deepcopy(Point_list[self.id])
  111. x = np.array([aim[0] - self_pot[0], aim[1] - self_pot[1]]) # 方向向量
  112. y = np.array([1, 0]) # x轴方向
  113. Lx = np.sqrt(x.dot(x)) # x.dot(x) 点乘自己,相当于向量模平方
  114. Ly = np.sqrt(y.dot(y))
  115. if Lx > self.MOVE_DISTANCE:
  116. cos_angle = x.dot(y) / (Lx * Ly)
  117. angle = np.arccos(cos_angle) # 0.....pi
  118. if x[0] >= 0 and x[1] >= 0:
  119. self_pot[0] = self_pot[0] + self.MOVE_DISTANCE * abs(np.cos(angle))
  120. self_pot[1] = self_pot[1] + self.MOVE_DISTANCE * np.sin(angle)
  121. elif x[0] <= 0 and x[1] >= 0:
  122. self_pot[0] = self_pot[0] - self.MOVE_DISTANCE * abs(np.cos(angle))
  123. self_pot[1] = self_pot[1] + self.MOVE_DISTANCE * np.sin(angle)
  124. elif x[0] <= 0 and x[1] <= 0:
  125. self_pot[0] = self_pot[0] - self.MOVE_DISTANCE * abs(np.cos(angle))
  126. self_pot[1] = self_pot[1] - self.MOVE_DISTANCE * np.sin(angle)
  127. else:
  128. self_pot[0] = self_pot[0] + self.MOVE_DISTANCE * abs(np.cos(angle))
  129. self_pot[1] = self_pot[1] - self.MOVE_DISTANCE * np.sin(angle)
  130. Point_list[self.id] = self_pot
  131. else:
  132. Point_list[self.id] = aim
  133. def occupy(self,nearest):
  134. for each in Point_list :
  135. d = self.distance_calculate(each,nearest)
  136. if d < self.JianCeError:
  137. ID = Point_list.index(each)
  138. return ID
  139. return None
  140. def send(self):
  141. '''self.MAXNUM = 2 ,则输出 1,0'''
  142. if self.MAXNUM <= 0:
  143. return None # 告诉询问着索要失败
  144. else:
  145. self.MAXNUM -= 1
  146. return self.MAXNUM
  147. obj_list = [Point(i) for i in range(0, NUM)] # 返回生成的NUM个对象的列表
  148. comp_li = None
  149. def gen(): # 绘图函数里面用的数据来源
  150. global comp_li
  151. while True:
  152. li = []
  153. for i in range(NUM):
  154. obj_list[i].decide()
  155. for each in Point_list:
  156. li.append(each)
  157. if comp_li == li:
  158. print('抵达边界完成,停留3秒')
  159. time.sleep(3)
  160. exit()
  161. else:comp_li = copy.deepcopy(li)
  162. with open('set.py','w') as f:
  163. f.write('POINT_LIST = '+ str(li))
  164. yield li
  165. def update(N_list):
  166. sx, sy = [], []
  167. for each in N_list:
  168. sx.append(each[0])
  169. sy.append(each[1])
  170. sc.set_offsets(np.c_[sx, sy])
  171. return sc
  172. ani = animation.FuncAnimation(fig, update, frames=gen, interval=1)
  173. plt.show()

初始分布随机生成:

抵达多边形后分布:

均匀化后分布:

均匀化算法思路:

class Point()
    def __init__(id):
        self.id = id
    def decide(): 
        '''决策函数,执行后更改全局变量 POINT_LIST '''
        return None

obj_list = [Point(i) for i in range(0, len(Point_list))]  # 返回生成的NUM个对象的列表    

while True:
    '''依次执行每个个体的决策函数,更改自身位置,迭代器返回全局变量 POINT_LIST'''
    for i in range(NUM):
        obj_list[i].decide()  
    yield POINT_LIST

    
###############################################################################################
关于决策函数:
def decide():
    """ mmid 指 前后邻点的中点 与 自己位置 相连的 中点 """
    找到前后邻点,计算出  mmid =((pre + next)/2 + my)/2  
    
    '''移到目标点'''
    move(mmid)
    
 ##################################################################################################
关于位置移动的处理 :

idea为了解决在顶点处移动无人机算法表达难度过大的问题提出将均匀多边形链表化的设想,即是把多边形等距划分,将每一个点位置存入链表中,移动无人机只需考虑其在链表上索引变动即可。

具体实现代码:

  1. '''重写 13 '''
  2. '''基本ok 只差停下函数'''
  3. '''哇 终于TM的停下来了'''
  4. import copy
  5. import numpy as np
  6. import matplotlib.pyplot as plt
  7. from matplotlib import animation
  8. import time
  9. from set import POINT_LIST
  10. Move_Distance = 20 # 20 * 0.01 =0.2
  11. Ting_Distance = 3
  12. # POINT_LIST = [[41.66666666666667, 25], [25, 41.66666666666667], [41.66666666666667, 75], [75, 25], [25, 75], [75, 58.33333333333333], [75, 75], [58.33333333333333, 75], [25, 25], [75, 41.66666666666667], [25, 58.33333333333333], [58.33333333333333, 25]]
  13. # Point_list = [[25, 50.0], [75, 43.75], [43.75, 25], [25, 75], [25, 43.75], [75, 68.75], [56.25, 25], [62.5, 75], [50.0, 25], [75, 62.5], [25, 68.75], [31.25, 75], [25, 25], [31.25, 25], [25, 31.25], [75, 50.0], [37.5, 25], [56.25, 75], [75, 25], [75, 75], [75, 31.25], [25, 62.5], [37.5, 75], [68.75, 25], [75, 37.5], [25, 37.5], [25, 56.25], [68.75, 75], [62.5, 25], [43.75, 75]]
  14. # Point_list = [[25, 25], [75, 75], [25, 75], [75, 25], [50, 25]]
  15. # Point_list = [[25, 43.75], [25, 56.25], [50.0, 25], [75, 37.5], [68.75, 75], [43.75, 75], [62.5, 25], [75, 43.75], [25, 75], [25, 25], [56.25, 25], [25, 68.75], [75, 50.0], [31.25, 75], [25, 62.5], [75, 68.75], [31.25, 25], [25, 31.25], [62.5, 75], [75, 62.5], [56.25, 75], [75, 56.25], [37.5, 25], [75, 25], [75, 31.25], [25, 37.5], [68.75, 25], [37.5, 75], [43.75, 25]]
  16. Point_list = POINT_LIST
  17. NUM = len(Point_list)
  18. # print(NUM)
  19. DING_LIST = [[25, 25], [75, 25], [75, 75], [25, 75]]
  20. DingX, DingY, x, y = [], [], [], []
  21. for each in DING_LIST:
  22. DingX.append(each[0])
  23. DingY.append(each[1])
  24. for each in Point_list:
  25. x.append(each[0])
  26. y.append(each[1])
  27. DingX.append(DING_LIST[0][0])
  28. DingY.append(DING_LIST[0][1])
  29. fig, ax = plt.subplots()
  30. ax.set_xlim(0, 100)
  31. ax.set_ylim(0, 100)
  32. sc = ax.scatter(x, y, color='r', alpha=0.7,marker='1',linewidth = 10)
  33. ax.plot(DingX, DingY, color = 'black',linestyle = ':')
  34. '''以间隔0.01生成齿轮链表'''
  35. def chain_make():
  36. Tooth_Chain = []
  37. Tooth_Chain.append([25, 25])
  38. for i in np.arange(25.01, 75, 0.01):
  39. Tooth_Chain.append([i, 25])
  40. Tooth_Chain.append([75, 25])
  41. for i in np.arange(25.01, 75, 0.01):
  42. Tooth_Chain.append([75, i])
  43. Tooth_Chain.append([75, 75])
  44. for i in np.arange(74.99, 25.0, -0.01):
  45. Tooth_Chain.append([round(i, 2), 75])
  46. Tooth_Chain.append([25, 75])
  47. for i in np.arange(74.99, 25, -0.01):
  48. Tooth_Chain.append([25, round(i, 2)])
  49. return Tooth_Chain
  50. def distance_calculate(A, B): # [1,1],[2,2] 得1.4142135623730951
  51. return pow(pow(abs(A[0] - B[0]), 2) + pow(abs(A[1] - B[1]), 2), 0.5)
  52. Tooth_Chain = chain_make()
  53. Tooth_Len = len(Tooth_Chain)
  54. Point_adindex = []
  55. for a in Point_list:
  56. for b in Tooth_Chain:
  57. d = distance_calculate(a, b)
  58. if d <= 0.005: # Point_list数据有问题
  59. a.append(Tooth_Chain.index(b))
  60. Point_adindex.append(a)
  61. # print(len(Point_adindex))
  62. def takeThird(elem):
  63. return elem[2]
  64. Point_adindex_sort = copy.deepcopy(Point_adindex)
  65. Point_adindex_sort.sort(key=takeThird)
  66. # print(len(Point_adindex_sort))
  67. class Point():
  68. next_dis = 200001
  69. def __init__(self, id):
  70. ''' self. pre_id next_id id 这三个是在Point_list中的位置'''
  71. self.id = id
  72. my_id = Point_adindex_sort.index(Point_adindex[self.id])
  73. if my_id == 0:
  74. self.pre_id = Point_adindex.index(Point_adindex_sort[NUM - 1])
  75. self.next_id = Point_adindex.index(Point_adindex_sort[1])
  76. elif my_id == NUM - 1:
  77. self.next_id = Point_adindex.index(Point_adindex_sort[0])
  78. self.pre_id = Point_adindex.index(Point_adindex_sort[NUM - 2])
  79. else:
  80. self.pre_id = Point_adindex.index(Point_adindex_sort[my_id - 1])
  81. self.next_id = Point_adindex.index(Point_adindex_sort[my_id + 1])
  82. def decide(self):
  83. pre_chain_index = Point_adindex[self.pre_id][2]
  84. next_chain_index = Point_adindex[self.next_id][2]
  85. self_chain_index = Point_adindex[self.id][2]
  86. if pre_chain_index < next_chain_index:
  87. a = pre_chain_index
  88. b = next_chain_index
  89. else:
  90. a = pre_chain_index
  91. b = next_chain_index + 20000
  92. if abs(self_chain_index - (a+b)/2 ) < 100 : pass
  93. else:
  94. if pre_chain_index < next_chain_index: # 正常情况
  95. self.next_dis = next_chain_index - self_chain_index
  96. mmid = ((next_chain_index + pre_chain_index) / 2 + self_chain_index) / 2
  97. # print('pre:', pre_chain_index, ' ', 'self', self_chain_index, ' ', 'next:', next_chain_index)
  98. else:
  99. self.next_dis = next_chain_index - self_chain_index + 20000
  100. if self.next_dis>= 20000 :
  101. self.next_dis -= 20000
  102. mmid = ((next_chain_index + Tooth_Len + pre_chain_index) / 2 + self_chain_index) / 2
  103. # print('pre:', pre_chain_index, ' ', 'self', self_chain_index, ' ', 'next:', next_chain_index)
  104. if abs(mmid - self_chain_index) <= Ting_Distance:
  105. if mmid % 1 == 0:
  106. self.move(int(mmid))
  107. elif self_chain_index > mmid: # 在目标顺市针方向
  108. self.move(int(mmid) + 1)
  109. else:
  110. self.move(int(mmid))
  111. elif mmid > self_chain_index:
  112. self.move(self_chain_index + Move_Distance)
  113. else:
  114. self.move(self_chain_index - Move_Distance)
  115. def move(self, aim):
  116. if aim >= Tooth_Len: aim -= Tooth_Len
  117. li = copy.deepcopy(Tooth_Chain[aim])
  118. li.append(aim)
  119. Point_adindex[self.id] = li
  120. def judge(list):
  121. d = 20000/NUM
  122. for each in list :
  123. if abs(each - d) > 100:
  124. return False
  125. return True
  126. def gen():
  127. while True:
  128. # print('$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$')
  129. li = []
  130. # panduanls=[]
  131. # if vari > ? :
  132. for i in range(NUM):
  133. obj_list[i].decide()
  134. # panduanls.append(obj_list[i].next_dis)
  135. # else:continue
  136. # if judge(panduanls):
  137. # print("均匀化分布算法执行完毕,停留3秒")
  138. # time.sleep(3)
  139. # exit()
  140. for each in Point_adindex: li.append(each[:-1])
  141. yield li
  142. def update(N_list):
  143. sx, sy = [], []
  144. for each in N_list:
  145. sx.append(each[0])
  146. sy.append(each[1])
  147. sc.set_offsets(np.c_[sx, sy])
  148. return sc
  149. obj_list = [Point(i) for i in range(0, len(Point_list))] # 返回生成的NUM个对象的列表
  150. ani = animation.FuncAnimation(fig, update, frames=gen, interval=2)
  151. plt.show()
  152. ###均匀化代码需要数据POINT_LIST,可以用代码中注释掉的数据看效果。

编队过程中碰撞问题解决办法:高度错开

三维效果演示:

三维演示代码已上传。

        

  1. 多智能体均匀多边形编队_哔哩哔哩_bilibili
  2. https://www.bilibili.com/video/BV1PE41117DG
  3. GitHub - ColaForced/AgentsMotionSimulation: 多智能体均匀多边形编队、追逐与合围。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/861870
推荐阅读
相关标签
  

闽ICP备14008679号