一、内容介绍
本节使用机器人任务分配的例子,来加深CBAA算法的理解。与用户购买商品类似,机器人希望分配到相应的距离最近的任务进行工作,假设机器人i的初始位置为,任务j的初始位置为
,那么相应的
,即越远的地方价值越低。假设机器人和任务目标的位置都已经给出,求出整个过程分配,使整体收获的价值最大。
二、代码解析
为了提高通用性,用类的方式来定义每个机器人,其包含的属性分别为第一节中介绍的x,y,J,c,其余算法与第一节介绍的相同,首先定义该类机器人的属性初始化
class CBAA_agent():
def __init__(self,state, id=0, task=None):
"""
c: individual score list
x: local assignment list
y: local winning bid list
state: state of the robot
"""
self.task_num = task.shape[0]
# Local Task Assignment List
self.x = [0 for i in range(self.task_num)]
# Local Winning Bid List
self.y = np.array([ -np.inf for _ in range(self.task_num)])
# This part can be modified depend on the problem
self.state = np.array([state])
self.c = -distance_matrix(self.state,task).squeeze() # Score (Euclidean Distance)
# Agent ID
self.id = id
在主函数部分,其写法为:
if __name__=="__main__":
task_num = 5
robot_num = 5
task = np.array([[0.4,0.3],[0.7,0.3],[0.4,0.7],[0.2,0.8],[0.1,0.9]])
state = np.array([[0.1,0.7],[0.4,0.9],[0.35,0.25],[0.33,0.44],[0.22,0.33]])
fig, ax = plt.subplots()
ax.set_xlim((-0.1, 1.1))
ax.set_ylim((-0.1, 1.1))
ax.plot(task[:, 0], task[:, 1], 'rx')
ax.plot(state[:,0],state[:,1], 'b^')
robot_list = [CBAA_agent(state[i],id=i, task=task) for i in range(robot_num)]
然后定义方法,对于每个机器人进行任务筛选方法,写为
def select_task(self):
if sum(self.x) == 0:
# Valid Task List
h = (self.c > self.y)
if h.any():
# Just for euclidean distance score (negative)
c = copy.deepcopy(self.c)
c[h==False] = -np.inf
self.J = np.argmax(c)
self.x[self.J] = 1
self.y[self.J] = self.c[self.J]
由于没有和其他机器人共享信息,在完成任务选择后,判断是否竞争成功,在主函数中,和其他机器人共享信息,代码如下:
def send_message(self):
"""
Return local winning bid list
[output]
y: winning bid list (list:task_num)
"""
return self.y.tolist()
# 下面为主函数部分
G = np.ones((robot_num, robot_num)) # Fully connected network\
# Configure network topology manually
# G[0,1]=0
# G[1,0]=0
t = 0 # Iteration number
assign_plots = []
while True:
converged_list = []
print("==Iteration {}==".format(t))
## Phase 1: Auction Process
print("Auction Process")
for robot_id , robot in enumerate(robot_list):
# select task by local information
robot.select_task()
# if t==0:
# assign_line, = ax.plot([robot.state[0][0],task[robot.J,0]],[robot.state[0][1],task[robot.J,1]],'k-',linewidth=2)
# assign_plots.append(assign_line)
# else:
# assign_plots[robot_id].set_data([robot.state[0][0],task[robot.J,0]],[robot.state[0][1],task[robot.J,1]])
print(robot.x)
## Phase 2: Consensus Process
# plt.pause(0.5)
print("Consensus Process")
# Send winning bid list to neighbors (depend on env)
message_pool = [robot.send_message() for robot in robot_list]
for robot_id, robot in enumerate(robot_list):
# Recieve winning bidlist from neighbors
g = G[robot_id]
connected, = np.where(g==1)
connected = list(connected)
connected.remove(robot_id)
if len(connected) > 0:
Y = {neighbor_id:message_pool[neighbor_id] for neighbor_id in connected}
else:
Y = None
# Update local information and decision
if Y is not None:
converged = robot.update_task(Y)
converged_list.append(converged)
print(robot.x)
在已知其他机器人的竞争信息后,更新任务
def update_task(self, Y=None):
"""
[input]
Y: winning bid lists from neighbors (dict:{neighbor_id:bid_list})
[output]
converged: True or False
"""
old_x = copy.deepcopy(self.x)
id_list = list(Y.keys())
id_list.insert(0, self.id)
y_list = np.array(list(Y.values()))
## Update local winning bid list
# When recive only one message
if len(y_list.shape)==1:
# make shape as (1,task_num)
y_list = y_list[None,:]
y_list = np.vstack((self.y[None,:],y_list))
self.y = y_list.max(0)
## Outbid check
# Winner w.r.t the updated local winning bid list
max_id = np.argmax(y_list[:,self.J])
z = id_list[max_id]
# If the agent is not the winner
if z != self.id:
# Release the assignment
self.x[self.J] = 0
converged = False
if old_x == self.x:
converged = True
return converged
整个任务的代码如图所示,结果给出
import numpy
import numpy as np
import copy
from scipy.spatial import distance_matrix
import matplotlib.pyplot as plt
class CBAA_agent():
def __init__(self,state, id=0, task=None):
"""
c: individual score list
x: local assignment list
y: local winning bid list
state: state of the robot
"""
self.task_num = task.shape[0]
# Local Task Assignment List
self.x = [0 for i in range(self.task_num)]
# Local Winning Bid List
self.y = np.array([ -np.inf for _ in range(self.task_num)])
# This part can be modified depend on the problem
self.state = np.array([state])
self.c = -distance_matrix(self.state,task).squeeze() # Score (Euclidean Distance)
# Agent ID
self.id = id
def select_task(self):
if sum(self.x) == 0:
# Valid Task List
h = (self.c > self.y)
if h.any():
# Just for euclidean distance score (negative)
c = copy.deepcopy(self.c)
c[h==False] = -np.inf
self.J = np.argmax(c)
self.x[self.J] = 1
self.y[self.J] = self.c[self.J]
def update_task(self, Y=None):
"""
[input]
Y: winning bid lists from neighbors (dict:{neighbor_id:bid_list})
[output]
converged: True or False
"""
old_x = copy.deepcopy(self.x)
id_list = list(Y.keys())
id_list.insert(0, self.id)
y_list = np.array(list(Y.values()))
## Update local winning bid list
# When recive only one message
if len(y_list.shape)==1:
# make shape as (1,task_num)
y_list = y_list[None,:]
y_list = np.vstack((self.y[None,:],y_list))
self.y = y_list.max(0)
## Outbid check
# Winner w.r.t the updated local winning bid list
max_id = np.argmax(y_list[:,self.J])
z = id_list[max_id]
# If the agent is not the winner
if z != self.id:
# Release the assignment
self.x[self.J] = 0
converged = False
if old_x == self.x:
converged = True
return converged
def send_message(self):
"""
Return local winning bid list
[output]
y: winning bid list (list:task_num)
"""
return self.y.tolist()
if __name__=="__main__":
task_num = 5
robot_num = 5
task = np.array([[0.4,0.3],[0.7,0.3],[0.4,0.7],[0.2,0.8],[0.1,0.9]])
state = np.array([[0.1,0.7],[0.4,0.9],[0.35,0.25],[0.33,0.44],[0.22,0.33]])
fig, ax = plt.subplots()
ax.set_xlim((-0.1, 1.1))
ax.set_ylim((-0.1, 1.1))
ax.plot(task[:, 0], task[:, 1], 'rx')
ax.plot(state[:,0],state[:,1], 'b^')
robot_list = [CBAA_agent(state[i],id=i, task=task) for i in range(robot_num)]
# Network Initialize
G = np.ones((robot_num, robot_num)) # Fully connected network\
# Configure network topology manually
# G[0,1]=0
# G[1,0]=0
t = 0 # Iteration number
assign_plots = []
while True:
converged_list = []
print("==Iteration {}==".format(t))
## Phase 1: Auction Process
print("Auction Process")
for robot_id , robot in enumerate(robot_list):
# select task by local information
robot.select_task()
# if t==0:
# assign_line, = ax.plot([robot.state[0][0],task[robot.J,0]],[robot.state[0][1],task[robot.J,1]],'k-',linewidth=2)
# assign_plots.append(assign_line)
# else:
# assign_plots[robot_id].set_data([robot.state[0][0],task[robot.J,0]],[robot.state[0][1],task[robot.J,1]])
print(robot.x)
## Phase 2: Consensus Process
# plt.pause(0.5)
print("Consensus Process")
# Send winning bid list to neighbors (depend on env)
message_pool = [robot.send_message() for robot in robot_list]
for robot_id, robot in enumerate(robot_list):
# Recieve winning bidlist from neighbors
g = G[robot_id]
connected, = np.where(g==1)
connected = list(connected)
connected.remove(robot_id)
if len(connected) > 0:
Y = {neighbor_id:message_pool[neighbor_id] for neighbor_id in connected}
else:
Y = None
# Update local information and decision
if Y is not None:
converged = robot.update_task(Y)
converged_list.append(converged)
print(robot.x)
t += 1
if sum(converged_list)==robot_num:
for robot_id, robot in enumerate(robot_list):
assign_line, = ax.plot([robot.state[0][0],task[robot.J,0]],[robot.state[0][1],task[robot.J,1]],'k-',linewidth=2)
assign_plots.append(assign_line)
dpi = 500
figure_size = (8,6)
plt.savefig('Solution.png',dpi=dpi,bbox_inches='tight')
plt.show()
break
print("CONVERGED")