├── README.md
└── Shape assembly code
├── Fcn_CalEnteringCmd.m
├── Fcn_CalExplorationCmd.m
├── Fcn_CalInteractionCmd.m
├── Fcn_GetNeighborSet.m
├── Fcn_GetPerformMetric.m
├── Fcn_NegotOrientState.m
├── Fcn_NegotPositState.m
├── Lib_AnimatFunctions.m
├── Lib_DrawingFunctions.m
├── Lib_InitialFunctions.m
├── Lib_RecordFunctions.m
├── Lib_ShapeFunctions.m
├── Lib_UpdateFunctions.m
├── MainLoop.m
└── ShapeImage
├── Image_geom_snow.mat
├── Image_geom_starfish.mat
├── Image_letter_B.mat
├── Image_letter_O.mat
└── Image_letter_R.mat
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
Mean-shift exploration in shape assembly of robot swarms
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 
15 |
16 |
17 |
18 | This file is the source code of our paper "Mean-shift exploration in shape assembly of robot swarms". It is coded by Matlab (R2020a).
19 |
20 |
21 | This file contains 16 m files and 1 folder.
22 |
23 | - MainLoop.m is the main program, which is used to set simulation parameters, start/stop simulation and animation.
24 | - Fcn_NegotPositState.m and Fcn_NegotOrientState are used to negotiate position and orientation of the target formation.
25 | - Fcn_CalEnteringCmd, Fcn_CalExplorationCmd, and Fcn_CalInteractionCmd are used to calculate shape-entering, shape-exploring, and interaction velocity commands, respectively.
26 | - Fcn_GetNeighborSet is used to calculate neighboring set, and Fcn_GetPerformMetric is used to calculate performance metrics.
27 | - Lib_InitialFunctions, Lib_ShapeFunctions, Lib_UpdateFunctions, Lib_AnimatFunctions, Lib_DrawingFunctions, and Lib_RecordFunctions are used for simulation initialization, shape processing, robot motion update, animated simulation, curve drawing, and data record.
28 | - The folder "ShapeImage" contains 4 different shapes, including snowflake, starfish, letter "R", letter "O", and letter "B".
29 |
30 | Note that simulation parameters may need to be readjusted depending on the swarm size and shape type.
31 |
32 | Please send all bug reports to authors.
33 |
34 | The authors may be contacted via:
35 |
36 | Shiyu Zhao
37 | Associate Professor
38 | Director of the Intelligent Unmanned Systems Laboratory
39 | School of Engineering, Westlake University
40 | Email: zhaoshiyu@westlake.edu.cn
41 |
42 | and
43 |
44 | Guibin Sun
45 | Postdoctoral Fellow
46 | School of Automation Science and Electrical Engineering
47 | Beihang University
48 | Email: sunguibinx@buaa.edu.cn
49 |
50 | @Copyright: If using this procedure for publications, please cite the article
51 | "Mean-shift selfless exploration in shape assembly of robot swarms".
52 |
53 | ## Citing
54 |
55 | If you find our work useful, please consider citing:
56 |
57 | ```BibTeX
58 | Sun, G., Zhou, R., Ma, Z. et al. Mean-shift exploration in shape assembly of robot swarms. Nat Commun 14, 3476 (2023). https://doi.org/10.1038/s41467-023-39251-5
59 | ```
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Shape assembly code/Fcn_CalEnteringCmd.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: calculate shape-entering velocity command
3 | function [cmd_set,grid_set]=Fcn_CalEnteringCmd(sim_param,shape_mtr,shape_info,robot_state,shape_state)
4 | % set proportional gain
5 | kappa=10.0;
6 | % robot-variable substitution
7 | t=sim_param.t;
8 | vel_max=sim_param.vel_max;
9 | swarm_size=sim_param.swarm_size;
10 | pos_set=robot_state.pos_set;
11 | % shape-variable substitution
12 | rn=shape_info.rn;
13 | cn=shape_info.cn;
14 | grid=shape_info.grid;
15 | cen_x=shape_info.cen_x;
16 | cen_y=shape_info.cen_y;
17 | shape_x=shape_mtr.shape_x;
18 | shape_y=shape_mtr.shape_y;
19 | shape_value=shape_mtr.shape_value;
20 | fpos_set=shape_state.pos_set;
21 | fvel_set=shape_state.vel_set;
22 | fhead_set=shape_state.head_set;
23 | % calculate local target position
24 | grid_set=zeros(size(pos_set));
25 | gpos_set=zeros(size(pos_set));
26 | gray_set=zeros(1,swarm_size);
27 | for index=1:1:swarm_size
28 | % locate robot in the local coordinate system
29 | location=TransGoalToLocal(pos_set(:,index),fpos_set(:,index),fhead_set(:,index),grid,cen_x,cen_y,rn,cn);
30 | % get gray color of the above location
31 | gray_color=GetGrayValue(location,shape_value);
32 | % calculate the local target point
33 | if gray_color==1 % robot is not in the gray grid
34 | goal_local=GetLocalTargetOut(location,pos_set(:,index),shape_x(:,:,index),shape_y(:,:,index),shape_value,rn);
35 | else % robot is in the gray grid
36 | delta=vel_max*t;
37 | range=ceil(delta/grid)+3;
38 | goal_local=GetLocalTargetIn(location,pos_set(:,index),shape_x(:,:,index),shape_y(:,:,index),shape_value,rn,cn,range);
39 | end
40 | grid_set(:,index)=[location(1),location(2)]';
41 | gpos_set(:,index)=goal_local;
42 | gray_set(:,index)=gray_color;
43 | end
44 | % calculate shape-entering command
45 | dist=sqrt((gpos_set(1,:)-pos_set(1,:)).^2+(gpos_set(2,:)-pos_set(2,:)).^2);
46 | dist(dist<=0)=1;
47 | cmd_set=kappa.*(gpos_set-pos_set).*(gray_set./dist)+fvel_set;
48 | end
49 |
50 | %% Auxiliary functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
51 | % FUNCTION: get local target location when robot is in the gray grid
52 | function goal_set=GetLocalTargetIn(location,pos_set,shape_x,shape_y,shape_value,rn,cn,range)
53 | % get local matrix for searching
54 | min_r=max(1,location(1)-range);
55 | max_r=min(rn,location(1)+range);
56 | min_c=max(1,location(2)-range);
57 | max_c=min(cn,location(2)+range);
58 | local_mtr=shape_value(min_r:max_r,min_c:max_c);
59 | % find the cell whose gray value is less than current gray value
60 | cen_r=location(1)-min_r+1;
61 | cen_c=location(2)-min_c+1;
62 | valid_mtr=zeros(size(local_mtr));
63 | gray_value=local_mtr(cen_r,cen_c);
64 | valid_mtr(local_mtr=1&x_grid<=cn);
137 | index_y=find(y_grid>=1&y_grid<=rn);
138 | inside(intersect(index_x,index_y))=1;
139 | location=[y_grid;x_grid;inside];
140 | end
141 |
142 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143 | % FUNCTION: limit angle
144 | function angle_s=LimitAngle(angle)
145 | angle(angle>pi)=angle(angle>pi)-2*pi;
146 | angle(angle<-pi)=angle(angle<-pi)+2*pi;
147 | angle_s=angle;
148 | end
149 |
--------------------------------------------------------------------------------
/Shape assembly code/Fcn_CalExplorationCmd.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: calculate shape-exploration velocity command
3 | function cmd_set=Fcn_CalExplorationCmd(sim_param,shape_mtr,shape_info,grid_set,neigh_mtr,robot_state,shape_state)
4 | % set proportional gain
5 | kappa_1=5.0;
6 | kappa_2=15.0;
7 | % robot variable substitution
8 | a_mtr=neigh_mtr.a_mtr;
9 | swarm_size=sim_param.swarm_size;
10 | r_body=sim_param.r_body;
11 | r_avoid=sim_param.r_avoid;
12 | r_sense=sim_param.r_sense;
13 | pos_set=robot_state.pos_set;
14 | % shape-variable substitution
15 | rn=shape_info.rn;
16 | cn=shape_info.cn;
17 | cen_x=shape_info.cen_x;
18 | cen_y=shape_info.cen_y;
19 | grid=shape_info.grid;
20 | shape_x=shape_mtr.shape_x;
21 | shape_y=shape_mtr.shape_y;
22 | shape_value=shape_mtr.shape_value;
23 | fpos_set=shape_state.pos_set;
24 | fhead_set=shape_state.head_set;
25 | % calculate mean point
26 | gfpos_set=zeros(size(pos_set));
27 | gepos_set=zeros(size(pos_set));
28 | robot_range=max(1,floor(max(r_avoid/2,r_body*2)/grid));
29 | neigh_range=ceil(r_sense/grid);
30 | for index=1:1:swarm_size
31 | % get mean point for filling action when there are both black and non-black cells around robot
32 | gfpos_set(:,index)=GetMeanPointFill(grid_set(:,index),pos_set(:,index),shape_x(:,:,index),shape_y(:,:,index),...
33 | shape_value,rn,cn,grid,neigh_range);
34 | % get mean point for exploring action when all the cells around robot are black
35 | gepos_set(:,index)=GetMeanPointExpl(index,grid_set(:,index),pos_set,shape_x(:,:,index),shape_y(:,:,index),...
36 | shape_value,rn,cn,cen_x,cen_y,grid,neigh_range,robot_range,a_mtr(index,:),fpos_set(:,index),fhead_set(:,index));
37 | end
38 | % calculate attractive force
39 | cmd_set=kappa_1.*(gfpos_set-pos_set)+kappa_2.*(gepos_set-pos_set);
40 | end
41 |
42 | %% Auxiliary functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 | % FUNCTION: get mean point for exploring action
44 | function goal_set=GetMeanPointExpl(index,grid_set,pos_set,shape_x,shape_y,shape_value,rn,cn,cen_x,cen_y,grid,neigh_range,robot_range,a_mtr,fpos_set,fhead_set)
45 | % get neighboring position
46 | pos_curr=pos_set(:,index);
47 | pos_neigh=pos_set(:,a_mtr==1);
48 | % initialize valid matrix
49 | valid_mtr=shape_value;
50 | valid_mtr(valid_mtr>0)=1;
51 | % determine the occupied cells by neigbors
52 | neigh_num=sum(a_mtr,2);
53 | for i=1:1:neigh_num
54 | % locate agent in the local coordinate system
55 | location=TransGoalToLocal(pos_neigh(:,i),fpos_set,fhead_set,grid,cen_x,cen_y,rn,cn);
56 | min_r=max(1,location(1)-robot_range);
57 | max_r=min(rn,location(1)+robot_range);
58 | min_c=max(1,location(2)-robot_range);
59 | max_c=min(cn,location(2)+robot_range);
60 | valid_mtr(min_r:max_r,min_c:max_c)=ones(max_r-min_r+1,max_c-min_c+1);
61 | end
62 | % get local matrix for searching
63 | min_r=max(1,grid_set(1)-neigh_range);
64 | max_r=min(rn,grid_set(1)+neigh_range);
65 | min_c=max(1,grid_set(2)-neigh_range);
66 | max_c=min(cn,grid_set(2)+neigh_range);
67 | local_mtr=valid_mtr(min_r:max_r,min_c:max_c);
68 | % get local matrix for searching
69 | [r_temp,c_temp]=find(local_mtr==0);
70 | r_index=r_temp+min_r-1;
71 | c_index=c_temp+min_c-1;
72 | gx_set=shape_x(sub2ind(size(shape_x),r_index',c_index'));
73 | gy_set=shape_y(sub2ind(size(shape_y),r_index',c_index'));
74 | temp_x=gx_set-pos_curr(1);
75 | temp_y=gy_set-pos_curr(2);
76 | dist_set=sqrt(temp_x.^2+temp_y.^2);
77 | weight=CalWeightFunction(dist_set,grid*neigh_range,0);
78 | temp=sum(weight,2);
79 | if temp==0
80 | goal_set=pos_curr;
81 | return
82 | end
83 | goal_x=sum(gx_set.*weight,2)/temp;
84 | goal_y=sum(gy_set.*weight,2)/temp;
85 | goal_set=[goal_x,goal_y]';
86 | if size(goal_set)==0
87 | goal_set=pos_set(:,index);
88 | end
89 | end
90 |
91 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 | % FUNCTION: get mean point for filling action
93 | function goal_set=GetMeanPointFill(grid_set,pos_set,shape_x,shape_y,shape_value,rn,cn,grid,neigh_range)
94 | % get local matrix for searching
95 | min_r=max(1,grid_set(1)-neigh_range);
96 | max_r=min(rn,grid_set(1)+neigh_range);
97 | min_c=max(1,grid_set(2)-neigh_range);
98 | max_c=min(cn,grid_set(2)+neigh_range);
99 | local_mtr=shape_value(min_r:max_r,min_c:max_c);
100 | local_mtr(local_mtr>0)=1;
101 | % calculate local grid in local matrix
102 | cen_r=grid_set(1)-min_r+1;
103 | cen_c=grid_set(2)-min_c+1;
104 | % get local matrix for searching
105 | [r_temp,c_temp]=find(local_mtr==0);
106 | r_index=r_temp-cen_r+grid_set(1);
107 | c_index=c_temp-cen_c+grid_set(2);
108 | gx_set=shape_x(sub2ind(size(shape_x),r_index',c_index'));
109 | gy_set=shape_y(sub2ind(size(shape_y),r_index',c_index'));
110 | temp_x=gx_set-pos_set(1);
111 | temp_y=gy_set-pos_set(2);
112 | dist_set=sqrt(temp_x.^2+temp_y.^2);
113 | weight=CalWeightFunction(dist_set,grid*neigh_range,0);
114 | temp=sum(weight,2);
115 | if temp==0
116 | goal_set=pos_set;
117 | return
118 | end
119 | goal_x=sum(gx_set.*weight,2)/temp;
120 | goal_y=sum(gy_set.*weight,2)/temp;
121 | goal_set=[goal_x,goal_y]';
122 | if size(goal_set)==0
123 | goal_set=pos_set;
124 | end
125 | end
126 |
127 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
128 | % FUNCTION: weight function
129 | function y=CalWeightFunction(x,r,s)
130 | y=(1+cos(pi.*(x-2*s)./(r-2*s)))/2;
131 | y(x<2*s)=1;
132 | y(x>r)=0;
133 | end
134 |
135 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136 | % FUNCTION: transform global position to local locations
137 | function location=TransGoalToLocal(pos_set,fpos_set,fhead_set,grid,cen_x,cen_y,rn,cn)
138 | % calculate the azimuth angle of robot to the formation center
139 | head_set=atan2(pos_set(2,:)-fpos_set(2),pos_set(1,:)-fpos_set(1));
140 | azim_set=head_set-fhead_set;
141 | azim_set=LimitAngle(azim_set);
142 | % calculate the distance between robot and formation center
143 | x_temp=(pos_set(1,:)-fpos_set(1)).^2;
144 | y_temp=(pos_set(2,:)-fpos_set(2)).^2;
145 | dist=sqrt(x_temp+y_temp);
146 | % get relative position of robot to the formation center
147 | x_coor=round(dist.*cos(azim_set)./grid);
148 | y_coor=round(dist.*sin(azim_set)./grid);
149 | % calculate the position of robot in the formation matrix
150 | x_grid=x_coor+cen_x;
151 | y_grid=rn-(y_coor+cen_y)+1;
152 | % determine whether the robot is in the formation matrix
153 | inside=zeros(1,length(x_grid));
154 | index_x=find(x_grid>=1&x_grid<=cn);
155 | index_y=find(y_grid>=1&y_grid<=rn);
156 | inside(intersect(index_x,index_y))=1;
157 | location=[y_grid;x_grid;inside];
158 | end
159 |
160 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
161 | % FUNCTION: limit angle
162 | function angle_s=LimitAngle(angle)
163 | angle(angle>pi)=angle(angle>pi)-2*pi;
164 | angle(angle<-pi)=angle(angle<-pi)+2*pi;
165 | angle_s=angle;
166 | end
167 |
--------------------------------------------------------------------------------
/Shape assembly code/Fcn_CalInteractionCmd.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: calculate interaction velocity command
3 | function cmd_set=Fcn_CalInteractionCmd(sim_param,neigh_mtr,robot_state)
4 | % set proportional gain
5 | kappa_1=25;
6 | kappa_2=1;
7 | % calculate avoidance command
8 | cmd_avoid=CalAvoidanceCmd(sim_param,neigh_mtr);
9 | % calculate consensus command
10 | cmd_conse=CalConsensusCmd(sim_param,neigh_mtr,robot_state);
11 | % calculate interaction command
12 | cmd_set=kappa_1.*cmd_avoid-kappa_2.*cmd_conse;
13 | end
14 |
15 | %% Auxiliary functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16 | % FUNCTION: calculate avoidance command
17 | function cmd_set=CalAvoidanceCmd(sim_param,neigh_mtr)
18 | % variable substitution
19 | r_avoid=sim_param.r_avoid;
20 | a_mtr=neigh_mtr.a_mtr;
21 | d_mtr=neigh_mtr.d_mtr;
22 | rx_mtr=neigh_mtr.rx_mtr;
23 | ry_mtr=neigh_mtr.ry_mtr;
24 | % calculate command
25 | dis_mtr=d_mtr+(~a_mtr).*r_avoid;
26 | temp=r_avoid-d_mtr;
27 | temp(temp<=0)=0;
28 | spr_mtr=temp./dis_mtr;
29 | unit_x=-rx_mtr./dis_mtr;
30 | unit_y=-ry_mtr./dis_mtr;
31 | cmd_x=sum(spr_mtr.*unit_x,2);
32 | cmd_y=sum(spr_mtr.*unit_y,2);
33 | cmd_set=[cmd_x';cmd_y'];
34 | end
35 |
36 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 | % FUNCTION: calculate consensus command
38 | function cmd_set=CalConsensusCmd(sim_param,neigh_mtr,robot_state)
39 | % variable substitution
40 | a_mtr=neigh_mtr.a_mtr;
41 | vel_set=robot_state.vel_set;
42 | swarm_size=sim_param.swarm_size;
43 | % calculate the relative velocity matrix
44 | vx_mtr=(vel_set(1,:)'*ones(1,swarm_size));
45 | vy_mtr=(vel_set(2,:)'*ones(1,swarm_size));
46 | vx_rel=(vx_mtr-vx_mtr').*a_mtr;
47 | vy_rel=(vy_mtr-vy_mtr').*a_mtr;
48 | % calculate control force
49 | cmd_x=sum(vx_rel,2);
50 | cmd_y=sum(vy_rel,2);
51 | neigh_num=sum(a_mtr,2);
52 | neigh_num(neigh_num==0)=1;
53 | cmd_set=[cmd_x';cmd_y']./neigh_num';
54 | end
--------------------------------------------------------------------------------
/Shape assembly code/Fcn_GetNeighborSet.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: get neighboring set
3 | function output=Fcn_GetNeighborSet(sim_param,robot_state)
4 | % variable substitution
5 | r_sense=sim_param.r_sense;
6 | swarm_size=sim_param.swarm_size;
7 | pos_set=robot_state.pos_set;
8 | % calculate distance matrix
9 | x_mtr=(pos_set(1,:)'*ones(1,swarm_size));
10 | y_mtr=(pos_set(2,:)'*ones(1,swarm_size));
11 | x_rel=x_mtr'-x_mtr;
12 | y_rel=y_mtr'-y_mtr;
13 | d_mtr=sqrt((x_rel).^2+(y_rel).^2);
14 | % calculate adjacent matrix
15 | a_temp=d_mtr<=(ones(swarm_size,swarm_size).*r_sense);
16 | a_mtr=a_temp-diag(ones(1,swarm_size));
17 | % output substitution
18 | output.a_mtr=a_mtr;
19 | output.d_mtr=d_mtr;
20 | output.rx_mtr=x_rel.*a_mtr;
21 | output.ry_mtr=y_rel.*a_mtr;
22 | end
--------------------------------------------------------------------------------
/Shape assembly code/Fcn_GetPerformMetric.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: get performance metric
3 | function metric=Fcn_GetPerformMetric(sim_param,neigh_mtr,robot_state,rcent_state,gray_mtr,gray_info)
4 | % variable substitution
5 | rn=gray_info.rn;
6 | cn=gray_info.cn;
7 | cen_x=gray_info.cen_x;
8 | cen_y=gray_info.cen_y;
9 | grid_size=gray_info.grid;
10 | gray_scale=gray_info.gray_scale;
11 | r_sense=sim_param.r_sense;
12 | swarm_size=sim_param.swarm_size;
13 | a_mtr=neigh_mtr.a_mtr;
14 | d_mtr=neigh_mtr.d_mtr;
15 | shape_value=gray_mtr(:,:,3);
16 | pos_set=robot_state.pos_set;
17 | vel_set=robot_state.vel_set;
18 | fpos_set=rcent_state.pos_set;
19 | fhead_set=rcent_state.head_set;
20 | % calculate the number of cells that have been covered
21 | num_ent=0;
22 | shape_value(shape_value>0)=1;
23 | cell_num=length(find(shape_value==0));
24 | robot_range=floor(sim_param.r_avoid/grid_size);
25 | for i=1:1:swarm_size
26 | % locate robot in the local coordinate system
27 | location=TransGoalToLocal(pos_set(:,i),fpos_set,fhead_set,grid_size,cen_x,cen_y,rn,cn);
28 | % get the distribution of robots in shape
29 | if location(3)
30 | min_r=max(1,location(1)-robot_range);
31 | max_r=min(rn,location(1)+robot_range);
32 | min_c=max(1,location(2)-robot_range);
33 | max_c=min(cn,location(2)+robot_range);
34 | shape_value(min_r:max_r,min_c:max_c)=ones(max_r-min_r+1,max_c-min_c+1);
35 | end
36 | % get gray level of this location
37 | shape_value_temp=gray_mtr(:,:,3);
38 | gray_value=GetGrayValue(location,shape_value_temp);
39 | % update the number of the entered robots
40 | if abs(gray_value)<=1.0/gray_scale
41 | num_ent=num_ent+1;
42 | else
43 | num_ent=num_ent+0;
44 | end
45 | end
46 | % calculate coverage rate M1
47 | void_num=length(find(shape_value==0));
48 | metric.cover_rate=(cell_num-void_num)/cell_num;
49 | % calculate entering rate M2
50 | metric.ent_rate=num_ent./swarm_size;
51 | % calculate distance variance M3
52 | ds_mtr=d_mtr.*a_mtr+r_sense.*(~a_mtr);
53 | min_set=min(ds_mtr');
54 | mean=sum(min_set,2)./swarm_size;
55 | derr_set=(min_set-mean).^2;
56 | metric.dist_var=sum(derr_set,2);
57 | % calculate mean velocity M4
58 | temp=sqrt(vel_set(1,:).^2+vel_set(2,:).^2);
59 | vel_norm=sum(temp,2);
60 | vel_norm(vel_norm==0)=1;
61 | temp=sum(vel_set,2);
62 | vel_sum=sqrt(temp'*temp);
63 | metric.mean_vel=vel_sum./vel_norm;
64 | end
65 |
66 | %% Auxiliary functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67 | % FUNCTION: get gray color of the given location
68 | function value=GetGrayValue(location,shape_value)
69 | if location(3)==0
70 | value=1;
71 | else
72 | value=shape_value(location(1),location(2));
73 | end
74 | end
75 |
76 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 | % FUNCTION: transform global position to local locations
78 | function location=TransGoalToLocal(pos_set,fpos_set,fhead_set,grid,cen_x,cen_y,rn,cn)
79 | % calculate the azimuth angle of robot to the formation center
80 | head_set=atan2(pos_set(2,:)-fpos_set(2),pos_set(1,:)-fpos_set(1));
81 | azim_set=head_set-fhead_set;
82 | azim_set=LimitAngle(azim_set);
83 | % calculate the distance between robot and formation center
84 | x_temp=(pos_set(1,:)-fpos_set(1)).^2;
85 | y_temp=(pos_set(2,:)-fpos_set(2)).^2;
86 | dist=sqrt(x_temp+y_temp);
87 | % get relative position of robot to the formation center
88 | x_coor=round(dist.*cos(azim_set)./grid);
89 | y_coor=round(dist.*sin(azim_set)./grid);
90 | % calculate the position of robot in the formation matrix
91 | x_grid=x_coor+cen_x;
92 | y_grid=rn-(y_coor+cen_y)+1;
93 | % determine whether the robot is in the formation matrix
94 | inside=zeros(1,length(x_grid));
95 | index_x=find(x_grid>=1&x_grid<=cn);
96 | index_y=find(y_grid>=1&y_grid<=rn);
97 | inside(intersect(index_x,index_y))=1;
98 | location=[y_grid;x_grid;inside];
99 | end
100 |
101 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102 | % FUNCTION: limit angle
103 | function angle_s=LimitAngle(angle)
104 | angle(angle>pi)=angle(angle>pi)-2*pi;
105 | angle(angle<-pi)=angle(angle<-pi)+2*pi;
106 | angle_s=angle;
107 | end
--------------------------------------------------------------------------------
/Shape assembly code/Fcn_NegotOrientState.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: negotiate formation orientation
3 | function state=Fcn_NegotOrientState(sim_param,neigh_mtr,shape_state,refer_state,inform_index)
4 | % set proportional gain
5 | kappa_conse=1.6;
6 | kappa_track=3.0;
7 | alpha=0.8;
8 | % variable substitution
9 | t=sim_param.t;
10 | a_mtr=neigh_mtr.a_mtr;
11 | head_set=shape_state.head_set;
12 | hvel_set=shape_state.hvel_set;
13 | ref_head=refer_state.head_set;
14 | ref_hvel=refer_state.hvel_set;
15 | swarm_size=sim_param.swarm_size;
16 | % calculate consensus command for all the robots
17 | err_set=GetConsensusError(swarm_size,a_mtr,head_set);
18 | [sign_set,pabs_set]=SepSymbAndValue(err_set);
19 | cmd_cons=kappa_conse.*sign_set.*(pabs_set.^alpha);
20 | % calculate reference-tracking command for informed robots
21 | cmd_track=(kappa_track.*(ref_head-head_set)+ref_hvel);
22 | % calculate alignment command for uninformed robots
23 | cmd_align=GetAlignConsensus(swarm_size,a_mtr,hvel_set);
24 | % get valid set of informed robots
25 | inform_set=zeros(1,swarm_size);
26 | inform_set(inform_index)=1;
27 | % calculate velocity command
28 | hvel_max=pi/2;
29 | cmd_set=-cmd_cons+inform_set.*cmd_track+(~inform_set).*cmd_align;
30 | cmd_set(cmd_set>hvel_max)=hvel_max;
31 | cmd_set(cmd_set<-hvel_max)=-hvel_max;
32 | % update negotiation movements
33 | state=shape_state;
34 | state.head_set=state.head_set+state.hvel_set.*t;
35 | state.hvel_set=cmd_set;
36 | end
37 |
38 | %% Auxiliary functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39 | % FUNCTION: calculate alignment consensus
40 | function cons_set=GetAlignConsensus(swarm_size,a_mtr,state_set)
41 | h_mtr=kron(state_set,ones(swarm_size,1));
42 | h_set=sum(h_mtr.*a_mtr,2);
43 | neigh_num=sum(a_mtr,2)';
44 | neigh_num(neigh_num==0)=1;
45 | cons_set=h_set'./neigh_num;
46 | end
47 |
48 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
49 | % FUNCTION: calculate consensus errors
50 | function [sign_set,abs_set]=SepSymbAndValue(value_set)
51 | sign_set=sign(value_set);
52 | abs_set=abs(value_set);
53 | end
54 |
55 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
56 | % FUNCTION: calculate consensus errors
57 | function err_set=GetConsensusError(swarm_size,a_mtr,state_set)
58 | h_mtr=kron(state_set,ones(swarm_size,1));
59 | h_rel=(h_mtr'-h_mtr).*a_mtr;
60 | neigh_num=sum(a_mtr,2)';
61 | neigh_num(neigh_num==0)=1;
62 | err_set=sum(h_rel,2)'./neigh_num;
63 | end
--------------------------------------------------------------------------------
/Shape assembly code/Fcn_NegotPositState.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: negotiate formation position
3 | function state=Fcn_NegotPositState(sim_param,neigh_mtr,shape_state,refer_state,inform_index)
4 | % set proportional gain
5 | kappa_conse=1.6;
6 | kappa_track=3.0;
7 | alpha=0.8;
8 | % variable substitution
9 | t=sim_param.t;
10 | a_mtr=neigh_mtr.a_mtr;
11 | pos_set=shape_state.pos_set;
12 | vel_set=shape_state.vel_set;
13 | ref_pos=refer_state.pos_set;
14 | ref_vel=refer_state.vel_set;
15 | swarm_size=sim_param.swarm_size;
16 | % calculate consensus command for all the robots
17 | err_set=GetConsensusError(swarm_size,a_mtr,pos_set);
18 | [sign_set,pabs_set]=SepSymbAndValue(err_set);
19 | cmd_cons=kappa_conse.*sign_set.*(pabs_set.^alpha);
20 | % calculate reference-tracking command for informed robots
21 | cmd_track=(kappa_track.*(ref_pos-pos_set)+ref_vel);
22 | % calculate alignment command for uninformed robots
23 | cmd_align=GetAlignConsensus(swarm_size,a_mtr,vel_set);
24 | % get valid set of informed robots
25 | inform_set=zeros(1,swarm_size);
26 | inform_set(inform_index)=1;
27 | % calculate velocity command
28 | cmd_set=-cmd_cons+inform_set.*cmd_track+(~inform_set).*cmd_align;
29 | % update negotiation movements
30 | state=shape_state;
31 | state.pos_set=state.pos_set+state.vel_set.*t;
32 | state.vel_set=cmd_set;
33 | end
34 |
35 | %% Auxiliary functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 | % FUNCTION: calculate alignment consensus
37 | function cons_set=GetAlignConsensus(swarm_size,a_mtr,state_set)
38 | x_mtr=kron(state_set(1,:),ones(swarm_size,1));
39 | y_mtr=kron(state_set(2,:),ones(swarm_size,1));
40 | x_set=sum(x_mtr.*a_mtr,2);
41 | y_set=sum(y_mtr.*a_mtr,2);
42 | neigh_num=sum(a_mtr,2)';
43 | neigh_num(neigh_num==0)=1;
44 | cons_set=[x_set,y_set]'./neigh_num;
45 | end
46 |
47 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
48 | % FUNCTION: calculate consensus errors
49 | function [sign_set,abs_set]=SepSymbAndValue(value_set)
50 | sign_set=sign(value_set);
51 | abs_set=abs(value_set);
52 | end
53 |
54 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
55 | % FUNCTION: calculate consensus errors
56 | function err_set=GetConsensusError(swarm_size,a_mtr,state_set)
57 | x_mtr=kron(state_set(1,:),ones(swarm_size,1));
58 | y_mtr=kron(state_set(2,:),ones(swarm_size,1));
59 | x_rel=(x_mtr'-x_mtr).*a_mtr;
60 | y_rel=(y_mtr'-y_mtr).*a_mtr;
61 | neigh_num=sum(a_mtr,2)';
62 | neigh_num(neigh_num==0)=1;
63 | err_set=[sum(x_rel,2),sum(y_rel,2)]'./neigh_num;
64 | end
65 |
--------------------------------------------------------------------------------
/Shape assembly code/Lib_AnimatFunctions.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: animated simulation functions
3 | function lib=Lib_AnimatFunctions
4 | global scale; scale=0.2;
5 | lib.InitAnimation=@InitAnimation;
6 | lib.UpadateAnimation=@UpadateAnimation;
7 | end
8 |
9 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10 | % FUNCTION: initialize animated simulation
11 | function hand_set=InitAnimation(draw_mode,sim_param,sim_range,robot_state,refer_state,shape_state,rcent_state,inform_index,shape_mtr,shape_info)
12 | % no drawing
13 | if draw_mode==0
14 | hand_set=false;
15 | return;
16 | end
17 | % initialize animation
18 | figure(1);
19 | box on; hold on; grid on; axis equal;
20 | set(gcf,'units','normalized','position',[0.05,0.05,0.9,0.85]);
21 | % draw objects
22 | switch draw_mode
23 | case 1 % draw robot swarm
24 | [hand_set.hr_pos,hand_set.hr_vel]=DrawReferMotion(sim_param.r_body,refer_state.pos_set,refer_state.vel_set);
25 | [hand_set.ha_pos,hand_set.ha_vel]=DrawRobotMotionA(sim_param.swarm_size,sim_param.r_body,robot_state.pos_set,robot_state.vel_set,inform_index);
26 | case 2 % draw negotiation
27 | hand_set.hs_pos=plot(shape_state.pos_set(1,:),shape_state.pos_set(2,:),'+','color',[0.9290 0.6940 0.1250],'markersize',3);
28 | hand_set.hc_pos=plot(rcent_state.pos_set(1,:),rcent_state.pos_set(2,:),'rs','markersize',8);
29 | [hand_set.ha_pos,hand_set.ha_vel]=DrawRobotMotionA(sim_param.swarm_size,sim_param.r_body,robot_state.pos_set,robot_state.vel_set,inform_index);
30 | case 3 % draw static shape
31 | hand_set.h_shape=DrawTargetShape(shape_mtr.size,shape_info.rn,shape_info.cn,shape_info.grid,shape_mtr);
32 | [hand_set.ha_pos,hand_set.ha_vel]=DrawRobotMotionB(sim_param.swarm_size,sim_param.r_body,robot_state.pos_set,robot_state.vel_set);
33 | end
34 | % set drawing properties
35 | xlabel('x axis (m)');
36 | ylabel('y axis (m)');
37 | set(gca,'FontSize',10,'Fontname','Times New Roman');
38 | axis(sim_range);
39 | set(gca,'xtick',sim_range(1):(sim_range(2)-sim_range(1))/4:sim_range(2));
40 | set(gca,'ytick',sim_range(3):(sim_range(4)-sim_range(3))/4:sim_range(4));
41 | end
42 |
43 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 | % FUNCTION: update animated simulation
45 | function hand_set=UpadateAnimation(hand_set,draw_mode,sim_param,robot_state,refer_state,shape_state,rcent_state)
46 | % no drawing
47 | if draw_mode==0
48 | return;
49 | end
50 | % update objects
51 | switch draw_mode
52 | case 1 % update robot swarm
53 | UpdateReferMotion(hand_set.hr_pos,hand_set.hr_vel,sim_param.r_body,refer_state.pos_set,refer_state.vel_set);
54 | UpdateRobotMotion(hand_set.ha_pos,hand_set.ha_vel,sim_param.swarm_size,sim_param.r_body,robot_state.pos_set,robot_state.vel_set);
55 | case 2 % update negotiation
56 | set(hand_set.hs_pos,'XData',shape_state.pos_set(1,:),'YData',shape_state.pos_set(2,:));
57 | set(hand_set.hc_pos,'XData',rcent_state.pos_set(1,:),'YData',rcent_state.pos_set(2,:));
58 | UpdateRobotMotion(hand_set.ha_pos,hand_set.ha_vel,sim_param.swarm_size,sim_param.r_body,robot_state.pos_set,robot_state.vel_set);
59 | case 3 % update static shape
60 | UpdateRobotMotion(hand_set.ha_pos,hand_set.ha_vel,sim_param.swarm_size,sim_param.r_body,robot_state.pos_set,robot_state.vel_set);
61 | end
62 | end
63 |
64 | %% Auxiliary functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65 | % FUNCTION: draw robots' movements
66 | function [ha_pos,ha_vel]=DrawRobotMotionA(swarm_size,r_body,pos_set,vel_set,inform_index)
67 | global scale;
68 | for index=1:1:swarm_size
69 | if ~ismember(index,inform_index)
70 | color=[0 0.4470 0.7410];
71 | else
72 | color=[0.8500 0.3250 0.0980];
73 | end
74 | rect=[pos_set(1,index)-r_body,pos_set(2,index)-r_body,2*r_body,2*r_body];
75 | ha_pos(index)=rectangle('Position',rect,'Curvature',[1,1],'EdgeColor',color);
76 | temp_x=[pos_set(1,index),pos_set(1,index)+scale.*vel_set(1,index)];
77 | temp_y=[pos_set(2,index),pos_set(2,index)+scale.*vel_set(2,index)];
78 | ha_vel(index)=plot(temp_x,temp_y,'r','linewidth',1.0);
79 | end
80 | end
81 |
82 | function [ha_pos,ha_vel]=DrawRobotMotionB(swarm_size,r_body,pos_set,vel_set)
83 | global scale;
84 | for index=1:1:swarm_size
85 | color=[0 0.4470 0.7410];
86 | rect=[pos_set(1,index)-r_body,pos_set(2,index)-r_body,2*r_body,2*r_body];
87 | ha_pos(index)=rectangle('Position',rect,'Curvature',[1,1],'EdgeColor',color);
88 | temp_x=[pos_set(1,index),pos_set(1,index)+scale.*vel_set(1,index)];
89 | temp_y=[pos_set(2,index),pos_set(2,index)+scale.*vel_set(2,index)];
90 | ha_vel(index)=plot(temp_x,temp_y,'r','linewidth',1.0);
91 | end
92 | end
93 |
94 | % FUNCTION: update robots' movements
95 | function UpdateRobotMotion(ha_pos,ha_vel,swarm_size,r_body,pos_set,vel_set)
96 | global scale;
97 | for index=1:1:swarm_size
98 | rect=[pos_set(1,index)-r_body,pos_set(2,index)-r_body,2*r_body,2*r_body];
99 | set(ha_pos(index),'Position',rect);
100 | temp_x=[pos_set(1,index),pos_set(1,index)+scale.*vel_set(1,index)];
101 | temp_y=[pos_set(2,index),pos_set(2,index)+scale.*vel_set(2,index)];
102 | set(ha_vel(index),'XData',temp_x,'YData',temp_y);
103 | end
104 | end
105 |
106 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107 | % FUNCTION: draw reference movement
108 | function [hr_pos,hr_vel]=DrawReferMotion(r_body,pos_set,vel_set)
109 | global scale;
110 | rect=[pos_set(1,:)-r_body,pos_set(2,:)-r_body,2*r_body,2*r_body];
111 | hr_pos=rectangle('Position',rect,'Curvature',[1,1],'EdgeColor','c','FaceColor','c');
112 | temp_x=[pos_set(1,:),pos_set(1,:)+scale.*vel_set(1,:)];
113 | temp_y=[pos_set(2,:),pos_set(2,:)+scale.*vel_set(2,:)];
114 | hr_vel=plot(temp_x,temp_y,'r','linewidth',1.0);
115 | end
116 |
117 | function UpdateReferMotion(hr_pos,hr_vel,r_body,pos_set,vel_set)
118 | global scale;
119 | rect=[pos_set(1,:)-r_body,pos_set(2,:)-r_body,2*r_body,2*r_body];
120 | set(hr_pos,'Position',rect);
121 | temp_x=[pos_set(1,:),pos_set(1,:)+scale.*vel_set(1,:)];
122 | temp_y=[pos_set(2,:),pos_set(2,:)+scale.*vel_set(2,:)];
123 | set(hr_vel,'XData',temp_x,'YData',temp_y);
124 | end
125 |
126 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
127 | % FUNCTION: draw formation
128 | function h_shape=DrawTargetShape(swarm_size,rn,cn,grid,shape_state)
129 | shape_x=shape_state.shape_x;
130 | shape_y=shape_state.shape_y;
131 | shape_value=shape_state.shape_value;
132 | shape_head=shape_state.shape_head;
133 | width=grid/2-grid/10;
134 | conut=1;
135 | for index=1:1:swarm_size
136 | color=rand(1,3);
137 | for i=1:1:rn
138 | for j=1:1:cn
139 | if shape_value(i,j)==0
140 | temp_x=[shape_x(i,j,index)-width,...
141 | shape_x(i,j,index)+width,...
142 | shape_x(i,j,index)+width,...
143 | shape_x(i,j,index)-width,...
144 | shape_x(i,j,index)-width];
145 | temp_y=[shape_y(i,j,index)-width,...
146 | shape_y(i,j,index)-width,...
147 | shape_y(i,j,index)+width,...
148 | shape_y(i,j,index)+width,...
149 | shape_y(i,j,index)-width];
150 | temp_px=(temp_x-shape_x(i,j,index)).*cos(pi*shape_head/180)-(temp_y-shape_y(i,j,index)).*sin(pi*shape_head/180)+shape_x(i,j,index);
151 | temp_py=(temp_x-shape_x(i,j,index)).*sin(pi*shape_head/180)+(temp_y-shape_y(i,j,index)).*cos(pi*shape_head/180)+shape_y(i,j,index);
152 | %h_shape(conut)=plot(temp_px,temp_py,'color',color);
153 | h_shape(conut)=plot(temp_px,temp_py,'color',[185 255 185]./255);
154 | conut=conut+1;
155 | %plot(shape_mtr(i,j,1),shape_mtr(i,j,2),'*','color',[0 0 255]./255);
156 | end
157 | end
158 | end
159 | end
160 | end
--------------------------------------------------------------------------------
/Shape assembly code/Lib_DrawingFunctions.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: drawing library
3 | function lib=Lib_DrawingFunctions
4 | lib.DrawNegotError=@DrawNegotError;
5 | lib.DrawTrajectory=@DrawTrajectory;
6 | lib.DrawPerfMetric=@DrawPerfMetric;
7 | end
8 |
9 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10 | % FUNCTION: draw performance metric
11 | function DrawPerfMetric(sim_param,record_state)
12 | % variable substitution
13 | t=sim_param.t;
14 | max_step=sim_param.max_step;
15 | cover_rate=record_state.cover_rate;
16 | ent_rate=record_state.ent_rate;
17 | dist_var=record_state.dist_var;
18 | % initialize drawing
19 | figure(4); box on; hold on; axis equal;
20 | % set drawing parameters
21 | line_width=2;
22 | aspect_ratio=7;
23 | time_set=(0:1:max_step)*t;
24 | % draw coverage rate
25 | subplot(3,1,1); box on; hold on; axis equal;
26 | plot(time_set,cover_rate','LineWidth',line_width);
27 | min_value=min(cover_rate);
28 | max_value=max(cover_rate);
29 | SetDrawLabel('Time (s)',['Coverage rate']);
30 | SetDrawRange([0,max_step*t,floor(min_value),ceil(max_value)],4,2,aspect_ratio);
31 | % draw entering rate
32 | subplot(3,1,2); box on; hold on; axis equal;
33 | plot(time_set,ent_rate','LineWidth',line_width);
34 | min_value=min(ent_rate);
35 | max_value=max(ent_rate);
36 | SetDrawLabel('Time (s)',['Entering rate']);
37 | SetDrawRange([0,max_step*t,floor(min_value),ceil(max_value)],4,2,aspect_ratio);
38 | % draw uniformity
39 | subplot(3,1,3); box on; hold on; axis equal;
40 | plot(time_set,dist_var','LineWidth',line_width);
41 | min_value=min(dist_var);
42 | max_value=max(dist_var);
43 | SetDrawLabel('Time (s)',['Uniformity']);
44 | SetDrawRange([0,max_step*t,floor(min_value),ceil(max_value)],4,2,aspect_ratio);
45 | end
46 |
47 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
48 | % FUNCTION: draw motion trajectory
49 | function DrawTrajectory(sim_param,sim_range,form_dyn,shape_info,record_state)
50 | % variable substitution
51 | swarm_size=sim_param.swarm_size;
52 | max_step=sim_param.max_step;
53 | ptra_rec=record_state.ptra_rec;
54 | pset_rec=record_state.pset_rec;
55 | vset_rec=record_state.vset_rec;
56 | % initialize drawing
57 | figure(3); box on; hold on; axis equal;
58 | %set(gcf,'units','normalized','position',[0.05,0.05,0.9,0.85]);
59 | % set drawing parameters
60 | scale=0.2;
61 | clarity=0.2;
62 | % draw target shape
63 | DrawTargetShape(form_dyn.size,shape_info.rn,shape_info.cn,shape_info.grid,form_dyn);
64 | % draw trajectory
65 | for index=1:1:swarm_size
66 | handle=plot(ptra_rec(1,1:max_step,index),ptra_rec(2,1:max_step,index),'LineWidth',1);
67 | handle.Color(4)=clarity;
68 | end
69 | % draw initial states
70 | pos_set=pset_rec(:,:,1);
71 | vel_set=vset_rec(:,:,1);
72 | DrawInitialMotion(scale,sim_param.swarm_size,sim_param.r_body,pos_set,vel_set);
73 | % draw final states
74 | pos_set=pset_rec(:,:,max_step);
75 | vel_set=vset_rec(:,:,max_step);
76 | DrawFinalMotion(scale,sim_param.swarm_size,sim_param.r_body,pos_set,vel_set);
77 | % set prperties
78 | SetDrawLabel('x axis (m)','y axis (m)');
79 | SetDrawRange(sim_range,2,2,1);
80 | end
81 |
82 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83 | % FUNCTION: draw negotiation errors
84 | function DrawNegotError(sim_param,record_state)
85 | % variable substitution
86 | t=sim_param.t;
87 | max_step=sim_param.max_step;
88 | swarm_size=sim_param.swarm_size;
89 | pos_set=record_state.spos_rec;
90 | head_set=record_state.shead_rec;
91 | ref_pos=record_state.rpos_rec;
92 | ref_head=record_state.rhead_rec;
93 | % initialize drawing
94 | figure(2); box on; hold on; axis equal;
95 | %set(gcf,'units','normalized','position',[0.05,0.05,0.9,0.85]);
96 | % set drawing parameters
97 | clarity=1.0;
98 | line_width=1.0;
99 | aspect_ratio=7;
100 | time_set=(0:1:max_step)*t;
101 | min_set=inf*ones(1,swarm_size);
102 | max_set=-inf*ones(1,swarm_size);
103 | % draw x-axis postion error
104 | subplot(3,1,1); box on; hold on; axis equal;
105 | for index=1:1:swarm_size
106 | rel_value=pos_set(1,:,index)-ref_pos(1,:);
107 | H=plot(time_set,rel_value,'LineWidth',line_width);
108 | H.Color(4)=clarity;
109 | min_set(:,index)=min(rel_value);
110 | max_set(:,index)=max(rel_value);
111 | end
112 | SetDrawLabel('Time (s)',['x-axis position' sprintf('\n' ) 'error (m)']);
113 | SetDrawRange([0,max_step*t,floor(min(min_set)),ceil(max(max_set))],4,2,aspect_ratio);
114 | % draw y-axis postion error
115 | subplot(3,1,2); box on; hold on; axis equal;
116 | for index=1:1:swarm_size
117 | rel_value=pos_set(2,:,index)-ref_pos(2,:);
118 | H=plot(time_set,rel_value,'LineWidth',line_width);
119 | H.Color(4)=clarity;
120 | min_set(:,index)=min(rel_value);
121 | max_set(:,index)=max(rel_value);
122 | end
123 | SetDrawLabel('Time (s)',['y-axis position' sprintf('\n' ) 'error (m)']);
124 | SetDrawRange([0,max_step*t,floor(min(min_set)),ceil(max(max_set))],4,2,aspect_ratio);
125 | % draw orientation error
126 | subplot(3,1,3); box on; hold on; axis equal;
127 | for index=1:1:swarm_size
128 | rel_value=head_set(:,index)-ref_head(:);
129 | H=plot(time_set,rel_value,'LineWidth',line_width);
130 | H.Color(4)=clarity;
131 | min_set(:,index)=min(rel_value);
132 | max_set(:,index)=max(rel_value);
133 | end
134 | SetDrawLabel('Time (s)',['Orientation' sprintf('\n' ) 'error (rad)']);
135 | SetDrawRange([0,max_step*t,floor(min(min_set)),ceil(max(max_set))],4,2,aspect_ratio);
136 | end
137 |
138 | %% Auxiliary functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139 |
140 |
141 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142 | % FUNCTION: set drawing range
143 | function SetDrawLabel(x_label,y_label)
144 | xlabel(x_label);
145 | ylabel(y_label);
146 | set(gca,'FontSize',10,'Fontname','Times New Roman');
147 | end
148 |
149 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150 | % FUNCTION: set drawing range
151 | function SetDrawRange(range,x_num,y_num,scale)
152 | axis(range);
153 | set(gca,'XTick',(range(1):(range(2)-range(1))/x_num:range(2)));
154 | set(gca,'YTick',(range(3):(range(4)-range(3))/y_num:range(4)));
155 | set(gca,'DataAspectRatio',[1 scale*(range(4)-range(3))/(range(2)-range(1)) 1]);
156 | end
157 |
158 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159 | % FUNCTION: draw robots' movements
160 | function DrawFinalMotion(scale,swarm_size,r_body,pos_set,vel_set)
161 | edge_color=[0 0.4470 0.7410];
162 | face_color=[0 0.4470 0.7410];
163 | for index=1:1:swarm_size
164 | rect=[pos_set(1,index)-r_body,pos_set(2,index)-r_body,2*r_body,2*r_body];
165 | rectangle('Position',rect,'Curvature',[1,1],'EdgeColor',edge_color,'FaceColor',face_color);
166 | temp_x=[pos_set(1,index),pos_set(1,index)+scale.*vel_set(1,index)];
167 | temp_y=[pos_set(2,index),pos_set(2,index)+scale.*vel_set(2,index)];
168 | plot(temp_x,temp_y,'r','linewidth',1.0);
169 | end
170 | end
171 |
172 | function DrawInitialMotion(scale,swarm_size,r_body,pos_set,vel_set)
173 | edge_color=[160 160 160]./255;
174 | face_color=[160 160 160]./255;
175 | for index=1:1:swarm_size
176 | rect=[pos_set(1,index)-r_body,pos_set(2,index)-r_body,2*r_body,2*r_body];
177 | rectangle('Position',rect,'Curvature',[1,1],'EdgeColor','none','FaceColor',face_color);
178 | temp_x=[pos_set(1,index),pos_set(1,index)+scale.*vel_set(1,index)];
179 | temp_y=[pos_set(2,index),pos_set(2,index)+scale.*vel_set(2,index)];
180 | plot(temp_x,temp_y,'r','linewidth',1.0);
181 | end
182 | end
183 |
184 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185 | % FUNCTION: draw formation
186 | function DrawTargetShape(swarm_size,rn,cn,grid,shape_state)
187 | shape_x=shape_state.shape_x;
188 | shape_y=shape_state.shape_y;
189 | shape_value=shape_state.shape_value;
190 | shape_head=shape_state.shape_head;
191 | width=grid/2-grid/10;
192 | color=[0.85 1 0.85];
193 | for index=1:1:swarm_size
194 | for i=1:1:rn
195 | for j=1:1:cn
196 | if shape_value(i,j)<=0.0%3
197 | temp_x=[shape_x(i,j,index)-width,...
198 | shape_x(i,j,index)+width,...
199 | shape_x(i,j,index)+width,...
200 | shape_x(i,j,index)-width,...
201 | shape_x(i,j,index)-width];
202 | temp_y=[shape_y(i,j,index)-width,...
203 | shape_y(i,j,index)-width,...
204 | shape_y(i,j,index)+width,...
205 | shape_y(i,j,index)+width,...
206 | shape_y(i,j,index)-width];
207 | temp_px=(temp_x-shape_x(i,j,index)).*cos(pi*shape_head/180)-(temp_y-shape_y(i,j,index)).*sin(pi*shape_head/180)+shape_x(i,j,index);
208 | temp_py=(temp_x-shape_x(i,j,index)).*sin(pi*shape_head/180)+(temp_y-shape_y(i,j,index)).*cos(pi*shape_head/180)+shape_y(i,j,index);
209 | patch(temp_px,temp_py,color,'EdgeColor',color);
210 | end
211 | end
212 | end
213 | end
214 | end
215 |
--------------------------------------------------------------------------------
/Shape assembly code/Lib_InitialFunctions.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: initialization functions
3 | function lib=Lib_InitialFunctions
4 | lib.InitSimuParam=@InitSimuParam;
5 | lib.SelectInformer=@SelectInformer;
6 | lib.InitRobotState=@InitRobotState;
7 | lib.InitReferState=@InitReferState;
8 | end
9 |
10 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11 | % FUNCTION: set simulation params
12 | function param=InitSimuParam(run_time,swarm_size)
13 | % set time params
14 | param.time=run_time; % runtime
15 | param.t=0.01; % period
16 | param.max_step=ceil(param.time/param.t); % cycles
17 | % set robot params
18 | param.r_body=0.20; % body size
19 | param.r_safe=0.35; % safe size
20 | param.r_avoid=1.5; % avoidance range
21 | param.r_sense=2.5; % sensing range
22 | param.vel_max=5; % max speed
23 | % set swarm params
24 | param.swarm_size=swarm_size; % swarm size
25 | param.leader_num=ceil(swarm_size/5); % number of leaders
26 | end
27 |
28 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29 | % FUNCTION: randomly select a given number of agents as informed robots
30 | function index=SelectInformer(sim_param)
31 | index=sort(randperm(sim_param.swarm_size,sim_param.leader_num));
32 | end
33 |
34 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 | % FUNCTION: initialize robots' states
36 | function state=InitRobotState(sim_param,pos_cen)
37 | state.pos_set=GetRobotPosition(sim_param,pos_cen);
38 | state.vel_set=zeros(2,sim_param.swarm_size);
39 | end
40 |
41 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 | % FUNCTION: initialize reference states
43 | function state=InitReferState(pos_cen)
44 | state.pos_set=pos_cen;
45 | state.vel_set=[0,0]';
46 | state.head_set=0;
47 | state.hvel_set=0;
48 | end
49 |
50 | %% Auxiliary functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
51 | % FUNCTION: get robots' positions
52 | function pos_set=GetRobotPosition(sim_param,pos_cen)
53 | % variable substitution
54 | swarm_size=sim_param.swarm_size;
55 | r_sense=sim_param.r_sense;
56 | r_avoid=sim_param.r_avoid;
57 | % initialize state variables
58 | pos_set=zeros(2,swarm_size);
59 | % initialize variables
60 | mtr_size=ceil(swarm_size/2+1);
61 | gen_mtr=zeros(mtr_size,mtr_size);
62 | gen_set=zeros(2,swarm_size);
63 | neigh_mtr=ones(3,3).*[-1,0,1];
64 | % generate the first state
65 | cell_pos=[ceil(mtr_size/2),ceil(mtr_size/2)]';
66 | gen_mtr(cell_pos(1),cell_pos(2))=1;
67 | gen_num=1;
68 | gen_set(:,gen_num)=cell_pos;
69 | % generate other states
70 | while gen_num~=swarm_size
71 | % select one from the generated cells
72 | index=randi([1,gen_num],1,1);
73 | cell_pos=gen_set(:,index);
74 | % find valid cells around the focus cell
75 | neigh_row=ones(3,3).*cell_pos(1)+neigh_mtr';
76 | neigh_col=ones(3,3).*cell_pos(2)+neigh_mtr;
77 | neigh_row=reshape(neigh_row,1,9);
78 | neigh_col=reshape(neigh_col,1,9);
79 | neigh_set=zeros(2,8);
80 | ungen_count=0;
81 | for i=1:1:9
82 | if isequal([neigh_row(i),neigh_col(i)]',cell_pos)
83 | continue;
84 | end
85 | if neigh_row(i)<1||neigh_row(i)>mtr_size||...
86 | neigh_col(i)<1||neigh_col(i)>mtr_size
87 | continue;
88 | end
89 | if gen_mtr(neigh_row(i),neigh_col(i))==1
90 | continue;
91 | end
92 | ungen_count=ungen_count+1;
93 | neigh_set(:,ungen_count)=[neigh_row(i),neigh_col(i)]';
94 | end
95 | % abandon the cell with many valid neighbors
96 | if ungen_count<3
97 | continue;
98 | end
99 | % choose a suitable cell
100 | suit_set=zeros(2,ungen_count);
101 | suit_count=0;
102 | for i=1:1:ungen_count
103 | cell_pos=neigh_set(:,i);
104 | neigh_row=ones(3,3).*cell_pos(1)+neigh_mtr';
105 | neigh_col=ones(3,3).*cell_pos(2)+neigh_mtr;
106 | neigh_row=reshape(neigh_row,1,9);
107 | neigh_col=reshape(neigh_col,1,9);
108 | gened_count=0;
109 | for j=1:1:9
110 | if neigh_row(j)<1||neigh_row(j)>mtr_size||...
111 | neigh_col(j)<1||neigh_col(j)>mtr_size
112 | continue;
113 | end
114 | if gen_mtr(neigh_row(j),neigh_col(j))==1
115 | gened_count=gened_count+1;
116 | end
117 | end
118 | if gened_count>=3
119 | continue;
120 | end
121 | suit_count=suit_count+1;
122 | suit_set(:,suit_count)=cell_pos;
123 | end
124 | if suit_count==0
125 | continue;
126 | end
127 | select=randi([1,suit_count],1,1);
128 | cell_pos=suit_set(:,select);
129 | gen_mtr(suit_set(1),suit_set(2))=1;
130 | gen_num=gen_num+1;
131 | gen_set(:,gen_num)=cell_pos;
132 | end
133 | % generate initial positions
134 | grid_lgth=r_sense/1.5/sqrt(2);
135 | grid_valid=grid_lgth-r_avoid/2;
136 | count=0;
137 | for i=1:1:mtr_size
138 | for j=1:1:mtr_size
139 | if gen_mtr(i,j)==0
140 | continue;
141 | end
142 | count=count+1;
143 | temp=[i,j]'-gen_set(:,1);
144 | temp_minx=temp(1)*grid_lgth-grid_valid/2; temp_maxx=temp(1)*grid_lgth+grid_valid/2;
145 | temp_miny=-temp(2)*grid_lgth-grid_valid/2; temp_maxy=-temp(2)*grid_lgth+grid_valid/2;
146 | pos_set(1,count)=temp_minx+(temp_maxx-temp_minx)*rand(1,1);
147 | pos_set(2,count)=temp_miny+(temp_maxy-temp_miny)*rand(1,1);
148 | end
149 | end
150 | pos_cen_temp=sum(pos_set,2)./swarm_size;
151 | pos_set=pos_set-pos_cen_temp+pos_cen;
152 | end
153 |
--------------------------------------------------------------------------------
/Shape assembly code/Lib_RecordFunctions.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: record library
3 | function lib=Lib_RecordFunctions
4 | lib.InitRecordState=@InitRecordState;
5 | lib.UpdateRecordState=@UpdateRecordState;
6 | end
7 |
8 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9 | % FUNCTION: initialize record states
10 | function state=InitRecordState(sim_param,robot_state,refer_state,shape_state,rcent_state,metric)
11 | % variable substitution
12 | swarm_size=sim_param.swarm_size;
13 | max_step=sim_param.max_step;
14 | % initialize robot-motion variables
15 | state.pset_rec=zeros(2,swarm_size,max_step+1);
16 | state.vset_rec=zeros(2,swarm_size,max_step+1);
17 | state.ptra_rec=zeros(2,max_step+1,swarm_size); % use for drawing trajectories
18 | state.vtra_rec=zeros(2,max_step+1,swarm_size);
19 | % initialize referecne variables
20 | state.rpos_rec=zeros(2,max_step+1);
21 | state.rvel_rec=zeros(2,max_step+1);
22 | state.rhead_rec=zeros(1,max_step+1);
23 | state.rhvel_rec=zeros(1,max_step+1);
24 | % initialize shape-motion variables
25 | state.spos_rec=zeros(2,max_step+1,swarm_size);
26 | state.svel_rec=zeros(2,max_step+1,swarm_size);
27 | state.shead_rec=zeros(max_step+1,swarm_size); % head angle
28 | state.shvel_rec=zeros(max_step+1,swarm_size); % head angular velocity
29 | state.spcen_rec=zeros(2,max_step+1);
30 | state.shcen_rec=zeros(2,max_step+1);
31 | % initialize metric variables
32 | state.cover_rate=zeros(1,max_step+1);
33 | state.ent_rate=zeros(1,max_step+1);
34 | state.dist_var=zeros(1,max_step+1);
35 | state.mean_vel=zeros(1,max_step+1);
36 | % record robot-motion variables
37 | state.pset_rec(:,:,1)=robot_state.pos_set;
38 | state.vset_rec(:,:,1)=robot_state.vel_set;
39 | state.ptra_rec(:,1,:)=robot_state.pos_set;
40 | state.vtra_rec(:,1,:)=robot_state.vel_set;
41 | % record referecne variables
42 | state.rpos_rec(:,1)=refer_state.pos_set;
43 | state.rvel_rec(:,1)=refer_state.vel_set;
44 | state.rhead_rec(:,1)=refer_state.head_set;
45 | state.rhvel_rec(:,1)=refer_state.hvel_set;
46 | % record shape-motion variables
47 | state.spos_rec(:,1,:)=shape_state.pos_set;
48 | state.svel_rec(:,1,:)=shape_state.vel_set;
49 | state.shead_rec(1,:)=shape_state.head_set;
50 | state.shvel_rec(1,:)=shape_state.hvel_set;
51 | state.spcen_rec(:,1)=rcent_state.pos_set;
52 | state.shcen_rec(:,1)=rcent_state.head_set;
53 | % record metric variables
54 | state.cover_rate(1,1)=metric.cover_rate;
55 | state.ent_rate(1,1)=metric.ent_rate;
56 | state.dist_var(1,1)=metric.dist_var;
57 | state.mean_vel(1,1)=metric.mean_vel;
58 | end
59 |
60 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61 | % FUNCTION: update record states
62 | function state=UpdateRecordState(step,record_state,robot_state,refer_state,shape_state,rcent_state,metric)
63 | % record robot-motion variables
64 | record_state.pset_rec(:,:,step+1)=robot_state.pos_set;
65 | record_state.vset_rec(:,:,step+1)=robot_state.vel_set;
66 | record_state.ptra_rec(:,step+1,:)=robot_state.pos_set;
67 | record_state.vtra_rec(:,step+1,:)=robot_state.vel_set;
68 | % record referecne variables
69 | record_state.rpos_rec(:,step+1)=refer_state.pos_set;
70 | record_state.rvel_rec(:,step+1)=refer_state.vel_set;
71 | record_state.rhead_rec(:,step+1)=refer_state.head_set;
72 | record_state.rhvel_rec(:,step+1)=refer_state.hvel_set;
73 | % record shape-motion variables
74 | record_state.spos_rec(:,step+1,:)=shape_state.pos_set;
75 | record_state.svel_rec(:,step+1,:)=shape_state.vel_set;
76 | record_state.shead_rec(step+1,:)=shape_state.head_set;
77 | record_state.shvel_rec(step+1,:)=shape_state.hvel_set;
78 | record_state.spcen_rec(:,step+1)=rcent_state.pos_set;
79 | record_state.shcen_rec(:,step+1)=rcent_state.head_set;
80 | % record metric variables
81 | record_state.cover_rate(1,step+1)=metric.cover_rate;
82 | record_state.ent_rate(1,step+1)=metric.ent_rate;
83 | record_state.dist_var(1,step+1)=metric.dist_var;
84 | record_state.mean_vel(1,step+1)=metric.mean_vel;
85 | % output substitution
86 | state=record_state;
87 | end
88 |
--------------------------------------------------------------------------------
/Shape assembly code/Lib_ShapeFunctions.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: shape processing library
3 | function lib=Lib_ShapeFunctions
4 | lib.LoadShapeImage=@LoadShapeImage;
5 | lib.InitFormShape=@InitFormShape;
6 | lib.InitFormState=@InitFormState;
7 | lib.GetShapeCenter=@GetShapeCenter;
8 | lib.GetDynFormation=@GetDynFormation;
9 | end
10 |
11 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12 | % FUNCTION: get dynamic formation
13 | function shape_dyn=GetDynFormation(swarm_size,shape_mtr,shape_info,shape_state)
14 | % variable substitution
15 | rn=shape_info.rn;
16 | cn=shape_info.cn;
17 | head_set=shape_state.head_set;
18 | pos_set=shape_state.pos_set;
19 | % initialize output
20 | shape_x=zeros(rn,cn,swarm_size);
21 | shape_y=zeros(rn,cn,swarm_size);
22 | shape_value=shape_mtr(:,:,3);
23 | % transform coordinate
24 | for i=1:1:swarm_size
25 | temp_mtr(:,:,1)=shape_mtr(:,:,1).*cos(head_set(i))-shape_mtr(:,:,2).*sin(head_set(i));
26 | temp_mtr(:,:,2)=shape_mtr(:,:,1).*sin(head_set(i))+shape_mtr(:,:,2).*cos(head_set(i));
27 | shape_x(:,:,i)=temp_mtr(:,:,1)+pos_set(1,i);
28 | shape_y(:,:,i)=temp_mtr(:,:,2)+pos_set(2,i);
29 | end
30 | % assign output
31 | shape_dyn.shape_x=shape_x;
32 | shape_dyn.shape_y=shape_y;
33 | shape_dyn.shape_value=shape_value;
34 | shape_dyn.shape_head=head_set;
35 | shape_dyn.size=swarm_size;
36 | end
37 |
38 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39 | % FUNCTION: get shape center
40 | function state=GetShapeCenter(swarm_size,shape_state)
41 | state.pos_set=sum(shape_state.pos_set,2)./swarm_size;
42 | state.head_set=sum(shape_state.head_set,2)./swarm_size;
43 | end
44 |
45 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
46 | % FUNCTION: initialize formation states
47 | function state=InitFormState(sim_param,robot_state)
48 | state.pos_set=robot_state.pos_set;
49 | state.vel_set=robot_state.vel_set;
50 | temp_head=rand(1,sim_param.swarm_size)*2*pi;
51 | aveg_head=sum(temp_head)/sim_param.swarm_size;
52 | aveg_head(aveg_head>2*pi)=aveg_head-2*pi;
53 | state.head_set=temp_head-aveg_head;
54 | state.hvel_set=zeros(size(state.head_set));
55 | end
56 |
57 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58 | % FUNCTION: initialize formation shape
59 | function [shape_mtr,shape_info]=InitFormShape(sim_param,image_mtr)
60 | % variable substitution
61 | swarm_size=sim_param.swarm_size;
62 | r_avoid=sim_param.r_avoid;
63 | % get parameters
64 | [shape_info.rn,shape_info.cn]=size(image_mtr);
65 | shape_info.cen_x=ceil(shape_info.cn/2);
66 | shape_info.cen_y=ceil(shape_info.rn/2);
67 | shape_info.black_num=length(find(image_mtr==0));
68 | shape_info.gray_num=length(find(image_mtr<1))-shape_info.black_num;
69 | temp_mtr=image_mtr(shape_info.cen_y,:);
70 | temp_mtr(temp_mtr==0)=2;
71 | shape_info.gray_scale=1/min(temp_mtr);
72 | % calculate grid size
73 | ratio=1.0;
74 | shape_info.grid=sqrt((pi/4)*(swarm_size/shape_info.black_num))*r_avoid;
75 | shape_info.grid=shape_info.grid*ratio;
76 | % get grid coordinates
77 | shape_mtr=ones(shape_info.rn,shape_info.cn,3);
78 | temp_x=((1:1:shape_info.cn)-shape_info.cen_x).*shape_info.grid;
79 | temp_y=((1:1:shape_info.rn)-shape_info.cen_y).*shape_info.grid;
80 | shape_mtr(:,:,1)=shape_mtr(:,:,1).*temp_x;
81 | shape_mtr(:,:,2)=shape_mtr(:,:,2).*flipud(temp_y');
82 | shape_mtr(:,:,3)=image_mtr;
83 | end
84 |
85 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86 | % FUNCTION: load shape image
87 | function image=LoadShapeImage(type)
88 | root_str='.\ShapeImage\';
89 | file_str='Image_';
90 | switch type
91 | case 1
92 | type_str='geom_snow';
93 | case 2
94 | type_str='geom_starfish';
95 | case 3
96 | type_str='letter_R';
97 | case 4
98 | type_str='letter_O';
99 | case 5
100 | type_str='letter_B';
101 | otherwise
102 | type_str='geom_snow';
103 | end
104 | % generate file path
105 | path=[root_str,file_str,type_str];
106 | temp=load(path);
107 | image=temp.gray_mtr;
108 | end
109 |
--------------------------------------------------------------------------------
/Shape assembly code/Lib_UpdateFunctions.m:
--------------------------------------------------------------------------------
1 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | % FUNCTION: update functions
3 | function lib=Lib_UpdateFunctions
4 | lib.UpdateRobotMotion=@UpdateRobotMotion;
5 | lib.UpdateRecordState=@UpdateRecordState;
6 | end
7 |
8 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9 | % FUNCTION: update robot motion
10 | function state=UpdateRobotMotion(sim_param,robot_state,cmd_set)
11 | % variable substitution
12 | t=sim_param.t;
13 | vel_max=sim_param.vel_max;
14 | pos_set=robot_state.pos_set;
15 | vel_set=robot_state.vel_set;
16 | % limit control input (max speed)
17 | vscl_set=sqrt(cmd_set(1,:).^2+cmd_set(2,:).^2);
18 | head_set=atan2(cmd_set(2,:),cmd_set(1,:));
19 | index_set=find(vscl_set>vel_max);
20 | cmd_set(:,index_set)=vel_max.*[cos(head_set(index_set));sin(head_set(index_set))];
21 | % upate motion states
22 | ratio=0.1;
23 | state.pos_set=pos_set+vel_set.*t;
24 | state.vel_set=ratio.*cmd_set+(1-ratio).*vel_set;
25 | end
26 |
27 |
--------------------------------------------------------------------------------
/Shape assembly code/MainLoop.m:
--------------------------------------------------------------------------------
1 | close all; clear; clc;
2 |
3 | %% Information %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4 | % AUTHORS: Guibin Sun, Beihang Universuty
5 | % INSTRUCTOR: Shiyu Zhao, Westlake University
6 | % TIME: 2020.9-2021.7
7 | % DECLARATION: Copyright @ Authors. All Rights Reserved.
8 |
9 | %% Initialization %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10 | % declare function library
11 | Init_lib=Lib_InitialFunctions; % use for simulation initialization
12 | Shape_lib=Lib_ShapeFunctions; % use for shape processing
13 | Updt_lib=Lib_UpdateFunctions; % use to update robot motion
14 | Anim_lib=Lib_AnimatFunctions; % use for animated simulation
15 | Draw_lib=Lib_DrawingFunctions; % use to draw curves
16 | Recd_lib=Lib_RecordFunctions; % use to record data
17 |
18 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19 | % set simulation params
20 | Run_time=20; % run time of simulation
21 | Swarm_size=50; % size of robot swarm
22 | Sim_range=[0,30,0,30]; % simulation range
23 | Sim_param=Init_lib.InitSimuParam(Run_time,Swarm_size);
24 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25 | % initialize robots' states
26 | Pos_init=[Sim_range(1)+(Sim_range(2)-Sim_range(1))/2,Sim_range(3)+(Sim_range(4)-Sim_range(3))/2]';
27 | Robot_state=Init_lib.InitRobotState(Sim_param,Pos_init);
28 | % initialize reference states
29 | Refer_state=Init_lib.InitReferState(Pos_init);
30 | % randomly select a given number of agents as informed robots
31 | Inform_index=Init_lib.SelectInformer(Sim_param);
32 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33 | % initialize formation shape
34 | Type=1; % shape type: 1-snowflake, 2-starfish, 3-letter R, 4-letter O, 5-letter B
35 | Gray_image=Shape_lib.LoadShapeImage(Type);
36 | [Gray_mtr,Gray_info]=Shape_lib.InitFormShape(Sim_param,Gray_image);
37 | % initialize formation states
38 | Shape_state=Shape_lib.InitFormState(Sim_param,Robot_state);
39 | % initialize shape center
40 | Rcent_state=Shape_lib.GetShapeCenter(Sim_param.swarm_size,Shape_state);
41 | % initialize performance metric
42 | Neigh_mtr=Fcn_GetNeighborSet(Sim_param,Robot_state);
43 | Metric=Fcn_GetPerformMetric(Sim_param,Neigh_mtr,Robot_state,Rcent_state,Gray_mtr,Gray_info);
44 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
45 | % initialize record states
46 | Record_state=Recd_lib.InitRecordState(Sim_param,Robot_state,Refer_state,Shape_state,Rcent_state,Metric);
47 |
48 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
49 | % initialize animated simulation
50 | Anim_mode=3; % 0-no drawing, 1-robot swarm, 2-negotiation, 3-static shape
51 | form_dyn=Shape_lib.GetDynFormation(1,Gray_mtr,Gray_info,Rcent_state);
52 | Hand_set=Anim_lib.InitAnimation(Anim_mode,Sim_param,Sim_range,Robot_state,Refer_state,Shape_state,Rcent_state,Inform_index,form_dyn,Gray_info);
53 | % set curves flags
54 | Draw_mode=3; % 0-no curve, 1-negotiation error, 2-motion trajectory, 3-performance metric
55 |
56 | %% Control Process %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57 | for step=1:1:Sim_param.max_step
58 | if Anim_mode==0&&rem(step,25)==0
59 | disp(['The simulation has been run ',num2str(step),' steps!']);
60 | end
61 |
62 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
63 | % get neighboring set
64 | Neigh_mtr=Fcn_GetNeighborSet(Sim_param,Robot_state);
65 |
66 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67 | % negotiate formation states
68 | state=Fcn_NegotPositState(Sim_param,Neigh_mtr,Shape_state,Refer_state,Inform_index);
69 | Shape_state=Fcn_NegotOrientState(Sim_param,Neigh_mtr,state,Refer_state,Inform_index);
70 | % get target formation
71 | Form_dyn=Shape_lib.GetDynFormation(Sim_param.swarm_size,Gray_mtr,Gray_info,Shape_state);
72 |
73 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74 | % calculate shape-entering command
75 | [cmd_enter,grid_set]=Fcn_CalEnteringCmd(Sim_param,Form_dyn,Gray_info,Robot_state,Shape_state);
76 | % calculate shape-exploration command
77 | cmd_explore=Fcn_CalExplorationCmd(Sim_param,Form_dyn,Gray_info,grid_set,Neigh_mtr,Robot_state,Shape_state);
78 | % calculate interaction velocity command
79 | cmd_interact=Fcn_CalInteractionCmd(Sim_param,Neigh_mtr,Robot_state);
80 | % calculate resultant command
81 | cmd_set=cmd_enter+cmd_explore+cmd_interact;
82 |
83 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84 | % update robot motion
85 | state=Updt_lib.UpdateRobotMotion(Sim_param,Robot_state,cmd_set);
86 | Robot_state=state;
87 | % update shape center
88 | Rcent_state=Shape_lib.GetShapeCenter(Sim_param.swarm_size,Shape_state);
89 | % update performance metric
90 | Metric=Fcn_GetPerformMetric(Sim_param,Neigh_mtr,Robot_state,Rcent_state,Gray_mtr,Gray_info);
91 | % update record state
92 | state=Recd_lib.UpdateRecordState(step,Record_state,Robot_state,Refer_state,Shape_state,Rcent_state,Metric);
93 | Record_state=state;
94 | % update animated simulation
95 | Anim_lib.UpadateAnimation(Hand_set,Anim_mode,Sim_param,Robot_state,Refer_state,Shape_state,Rcent_state);
96 | drawnow;
97 | end
98 |
99 | %% Curves Drawing %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 | switch Draw_mode
101 | case 1
102 | Draw_lib.DrawNegotError(Sim_param,Record_state);
103 | case 2
104 | form_dyn=Shape_lib.GetDynFormation(1,Gray_mtr,Gray_info,Rcent_state);
105 | Draw_lib.DrawTrajectory(Sim_param,Sim_range,form_dyn,Gray_info,Record_state);
106 | case 3
107 | Draw_lib.DrawPerfMetric(Sim_param,Record_state);
108 | end
109 |
--------------------------------------------------------------------------------
/Shape assembly code/ShapeImage/Image_geom_snow.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WindyLab/Shape-assembly-code/5da27db8687badd025502b8da9ede2f7f30feac4/Shape assembly code/ShapeImage/Image_geom_snow.mat
--------------------------------------------------------------------------------
/Shape assembly code/ShapeImage/Image_geom_starfish.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WindyLab/Shape-assembly-code/5da27db8687badd025502b8da9ede2f7f30feac4/Shape assembly code/ShapeImage/Image_geom_starfish.mat
--------------------------------------------------------------------------------
/Shape assembly code/ShapeImage/Image_letter_B.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WindyLab/Shape-assembly-code/5da27db8687badd025502b8da9ede2f7f30feac4/Shape assembly code/ShapeImage/Image_letter_B.mat
--------------------------------------------------------------------------------
/Shape assembly code/ShapeImage/Image_letter_O.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WindyLab/Shape-assembly-code/5da27db8687badd025502b8da9ede2f7f30feac4/Shape assembly code/ShapeImage/Image_letter_O.mat
--------------------------------------------------------------------------------
/Shape assembly code/ShapeImage/Image_letter_R.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WindyLab/Shape-assembly-code/5da27db8687badd025502b8da9ede2f7f30feac4/Shape assembly code/ShapeImage/Image_letter_R.mat
--------------------------------------------------------------------------------