├── 1-Non-Obstacles
├── 10-10pathLength.xlsx
├── 20-17pathLength.xlsx
├── ACOPathPlanning_V1.m
├── ConvertXY.m
├── Note.md
├── calcHeuristic.m
├── delta_r2s.m
├── eta.xlsx
├── globalDelta.xlsx
├── globalDelta_Bug.xlsx
├── indexing.m
└── showPath.m
├── 2-LineObstacles
├── ACOPathPlanning.m
├── ConvertXY.m
├── Iterations.jpg
├── Log.md
├── Results
│ ├── Length-Iteration__relativeImportance4.jpg
│ ├── Length-Iteration_newPheromoneupdate.jpg
│ ├── robotPath_newPheromoneupdate.jpg
│ └── robotPath_relativeImportance4.jpg
├── calcDelta.m
├── calcHeuristic.m
├── indexing.m
├── robotPathRecords.jpg
├── showLength.m
└── showPath.m
├── 3 - Convergence
└── Log.md
├── 4 - Final Stage
└── Log.md
├── README.md
└── image
├── ACO Flowchart.png
├── ACOProjectLogo.png
├── Demo.gif
├── Map-Algorithm Boxchart.jpg
├── Map3.jpg
├── Map_Easy.png
├── Map_Hard.png
├── Min Path Length-Data (1).jpg
├── Min path length - data.jpg
├── ParaSelec_ACS_Mark.jpg
├── ParaSelec_MMAS_1.jpg
├── ParaSelec_eAS_1.png
├── PathPlanningAlgorithmsOverview.png
├── PerformanceAnalysis_CS.png
├── PerformanceAnalysis_Runtime.png
├── Route Map (1).jpg
├── Route Map (2).jpg
├── Route Map.jpg
├── aco_diagram.jpg
├── converge_map1.png
├── converge_map2.png
├── final_demo.gif
├── image_log.md
├── matlab.png
├── route_map1.png
└── route_map2.png
/1-Non-Obstacles/10-10pathLength.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlyEugeneLi/ACO-RobotPathPlanning-MATLAB/cb5c0c694d91860b83171b91530f74c3ea0f1ac4/1-Non-Obstacles/10-10pathLength.xlsx
--------------------------------------------------------------------------------
/1-Non-Obstacles/20-17pathLength.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlyEugeneLi/ACO-RobotPathPlanning-MATLAB/cb5c0c694d91860b83171b91530f74c3ea0f1ac4/1-Non-Obstacles/20-17pathLength.xlsx
--------------------------------------------------------------------------------
/1-Non-Obstacles/ACOPathPlanning_V1.m:
--------------------------------------------------------------------------------
1 | % Title: Ant Colony Optimisation algorithms for Robot Path Planning
2 | % Author: Yujin Li
3 | % Date: Sunday 13 March 2022
4 | clc;
5 | clear all;
6 | close all;
7 | % 1. INITIALISATION
8 | % 1.1. Environment
9 | SIZE = 10;
10 | gridMap = zeros(SIZE); % Environment configuration: 0 for clear path, 1 for obstacles
11 | % 1.2. Parameters:
12 | % pheromone, delta pheromone: inverse of the total path length,
13 | % heuristic values, number of ants, generations of ants, Alpha: evaporation
14 | % rate, Beta: relative importance of pheromone versus distance
15 | numAnts = 17; % the number of ants in a colony
16 | numGen = 20; % the number of generations (iterations)
17 | tau = ones(SIZE*SIZE); % Pheromone Matrix Tau(r,s): amount of pheromone on
18 | % the edge from grid r to grid s. In this case, the
19 | % first column represents all the grid r and the
20 | % first row represents all the grid s, where s must
21 | % belong to J_k(r), which is a set of cities that
22 | % remain to be visited by ant k positioned on city r
23 |
24 | tau = 8.*tau; % Set the initial pheromone of all edges (r,s) as 8
25 | alpha = 0.3; % the Evaporation rate of pheromone
26 | beta = 7; % the relative importance beta
27 | home = 1; % the starting point -- home of the robot
28 | destination = SIZE*SIZE; % destination location
29 | minTourLength = inf; % the length of the shortest path
30 | bestGen = 0; % the generation that finds the shortest path
31 | bestAnt = 0; % the ant that finds the shortest path within current generation
32 | globalDelta = delta_r2s(gridMap); % cost required from r to s
33 | % T_delta = table(globalDelta);
34 | % writetable(T_delta, 'globalDelta.xlsx', 'sheet', 1, 'Range', 'A1');
35 | eta = zeros(SIZE); % Heuristic value Matrix Eta(r,s), s belongs to J_k(r)
36 | eta = calcHeuristic(eta, destination); % Initialise Heuristic value
37 | % T_eta = table(eta);
38 | % writetable(T_eta, 'eta.xlsx', 'Sheet', 1, 'Range', 'A1');
39 | % edge = 1; % the size of the square grid( the length of the edge)
40 | pathStorage = cell(numGen, numAnts);
41 | pathLength = zeros(numGen, numAnts);
42 |
43 | % 2. STATE TRANSITION
44 | % 2.1 Initialisation
45 | for Gen = 1:numGen % Outter Loop: How many times ants go out and forage
46 | for Ant = 1:numAnts % Inner Loop: How many ants each time
47 | currGrid = home; % Store the current grid where the ant is located
48 | pathRecord = home; % Store the grids that the ant has walked through
49 | toBeVisited = ones(SIZE); % cities that remain to be visited by ant
50 | % k positioned on city r; 0 for visited,
51 | % 1 for to be visited
52 | toBeVisited(currGrid) = 0; % Mark the home grid as visited so it won't repeat
53 | localDelta = globalDelta;
54 | indexDelta = indexing(localDelta, currGrid, toBeVisited); % find indices of local available surrounding grids
55 | numAvailable = length(indexDelta); % the total number of the local available grids < 8
56 | counter = 1;
57 | % 2.2 The ant start finding path to destination
58 | while (currGrid ~= destination && numAvailable >= 1)
59 | % 2.2.1 Calculate the probability of choosing the certain grids based on
60 | % tau and eta
61 | stateTransProb = zeros(numAvailable, 1);
62 | for i = 1: numAvailable
63 | stateTransProb(i) = tau(currGrid, indexDelta(i)) * eta(indexDelta(i))^beta;
64 | end
65 | sumProb = sum(stateTransProb);
66 | stateTransProb = stateTransProb / sumProb;
67 | % 2.2.2 Roulette wheel selection algorithm: to choose the next grid randomly
68 | wheelProb = zeros(numAvailable, 1);
69 | wheelProb(1) = stateTransProb(1);
70 | for i = 2:numAvailable
71 | if i ~= numAvailable
72 | wheelProb(i) = wheelProb(i-1) + stateTransProb(i);
73 | else
74 | wheelProb(numAvailable) = 1;
75 | end
76 | end
77 | wheelHand = find(wheelProb >= rand, 1); % Turn the wheel and wait for the result
78 | nextGrid = indexDelta(wheelHand(1)); % Decide the next grid
79 | % 2.2.3 Store the result: the new grid, the updated length
80 | pathRecord(end + 1) = nextGrid; % Concatenate the new grid
81 | pathLength(Gen, Ant) = pathLength(Gen, Ant) + localDelta(currGrid, nextGrid);
82 | currGrid = nextGrid; % Move to the next grid
83 | % 2.2.4 Update J_k(r) and corresponding localDelta to prepare for the next move
84 | toBeVisited(currGrid) = 0;
85 | for i = 1:size(localDelta, 1)
86 | if toBeVisited(i) == 0
87 | localDelta(currGrid, i) = 0;
88 | localDelta(i, currGrid) = 0;
89 | end
90 | end
91 | indexDelta = indexing(localDelta, currGrid, toBeVisited);
92 | numAvailable = length(indexDelta);
93 | counter = counter + 1;
94 | end % the ant reaches to the destination and stop the loop
95 | % 2.3 Record the job done by the ant
96 | pathStorage{Gen, Ant} = pathRecord; % Save the path
97 | if pathRecord(end) == destination
98 | if pathLength(Gen, Ant) < minTourLength % Does the ant find a shorter path?
99 | minTourLength = pathLength(Gen, Ant); % Yes, save the new shortest path
100 | bestGen = Gen; % Remember the generation that achieved this
101 | bestAnt = Ant; % Remember the ant that achieved this
102 | end
103 | else % When the ant is not successful, offset its length in this iteration
104 | pathLength(Gen, Ant) = 0;
105 | end
106 | end % The ant finishes the forage this time
107 | % 2.4 Update the intensity of pheromone on the path
108 | deltaTau = zeros(size(tau));
109 | for i = 1: numAnts
110 | if pathLength(Gen, Ant)
111 | pathTemp = pathStorage{Gen, Ant};
112 | pathInterval = length(pathTemp) - 1;
113 | for j = 1: pathInterval
114 | deltaTau(pathTemp(j), pathTemp(j + 1)) = 1 / pathLength(Gen, Ant);
115 | deltaTau(pathTemp(j + 1), pathTemp(j)) = 1 / pathLength(Gen, Ant);
116 | end
117 | end
118 | end
119 | tau = (1 - alpha) .* tau + deltaTau; % pheromone evaporation rule
120 | end % All the ants in this generation finished forage; restart a new generation now
121 |
122 | % 3. VISUALISATION
123 | showPath(gridMap,SIZE, pathStorage, bestGen, bestAnt);
124 |
--------------------------------------------------------------------------------
/1-Non-Obstacles/ConvertXY.m:
--------------------------------------------------------------------------------
1 | function [x, y] = ConvertXY(gridNum, rowMap) % Extract x coordinate from the serial number of the location
2 | x = ceil(gridNum / rowMap) - 0.5;
3 | y = rowMap - mod(gridNum, rowMap) + 0.5;
4 | if y == rowMap + 0.5
5 | y = 0.5;
6 | end
7 | end
8 |
9 |
--------------------------------------------------------------------------------
/1-Non-Obstacles/Note.md:
--------------------------------------------------------------------------------
1 | This is the 1st working code
2 |
--------------------------------------------------------------------------------
/1-Non-Obstacles/calcHeuristic.m:
--------------------------------------------------------------------------------
1 | function Eta = calcHeuristic(arr, grid)
2 | dim1 = size(arr, 1);
3 | dim2 = size(arr, 1) * size(arr, 1);
4 | for i = 1:dim2
5 | [desti_x, desti_y] = ConvertXY(grid, dim1);
6 | [x, y] = ConvertXY(i, dim1);
7 | distance = sqrt((x - desti_x)^2 + (y - desti_y)^2);
8 | if i ~= grid
9 | arr(i) = 1 / distance;
10 | else
11 | arr(grid) = 100;
12 | end
13 | end
14 | Eta = arr;
15 | end
16 |
17 |
--------------------------------------------------------------------------------
/1-Non-Obstacles/delta_r2s.m:
--------------------------------------------------------------------------------
1 | function D = delta_r2s(arr) % delta_(r,s): cost from grid r to grid s
2 | % r and s must be next to each other ssss
3 | row = size(arr, 1); % the number of rows of the array
4 | column = size(arr, 2);
5 | D = zeros(row*column); % initialise the delta_(r,s) matrix
6 | % Outer Loop
7 | for i = 1:row
8 | for j = 1:column % Outter Loop: Traverse all the grids to set their cost
9 | % of traveling to the local surrouding grids
10 | if arr(i, j) == 0 % grid r must not be a obstacle
11 |
12 | % Inner Loop
13 | for x = 1:row
14 | for y = 1:column % Inner Loop: find the surrounding available
15 | % grids s and return the cost value
16 | % (distance) to the exact variable in
17 | % the matrix
18 | if arr(x, y) == 0 % the surrounding grid must be clear
19 | rel_x = abs(i - x); % relative distance between grid r and s on x direction
20 | rel_y = abs(j - y); % relative distance between grid r and s on y direction
21 | if rel_x + rel_y == 1 || (rel_x == 1 && rel_y == 1)
22 | % When this grid is one of the adjacent
23 | % grids in 8 directions
24 | D((i-1)*column + j, (x-1)*column + y) = sqrt(rel_x^2 + rel_y^2);
25 | % D(r, s), r and s are indices of one-dimensional matrix
26 | % Return relative distance between r and s
27 | end
28 | end
29 | end
30 | end
31 | end
32 | end
33 | end
34 |
35 | end
36 |
37 |
--------------------------------------------------------------------------------
/1-Non-Obstacles/eta.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlyEugeneLi/ACO-RobotPathPlanning-MATLAB/cb5c0c694d91860b83171b91530f74c3ea0f1ac4/1-Non-Obstacles/eta.xlsx
--------------------------------------------------------------------------------
/1-Non-Obstacles/globalDelta.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlyEugeneLi/ACO-RobotPathPlanning-MATLAB/cb5c0c694d91860b83171b91530f74c3ea0f1ac4/1-Non-Obstacles/globalDelta.xlsx
--------------------------------------------------------------------------------
/1-Non-Obstacles/globalDelta_Bug.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlyEugeneLi/ACO-RobotPathPlanning-MATLAB/cb5c0c694d91860b83171b91530f74c3ea0f1ac4/1-Non-Obstacles/globalDelta_Bug.xlsx
--------------------------------------------------------------------------------
/1-Non-Obstacles/indexing.m:
--------------------------------------------------------------------------------
1 | function index = indexing(delta, grid, J_kr) % Return the indices of available grids
2 | index = delta(grid, :); % Store the cost required to the next gird
3 | arr = find(index); % Scope down available adjacent grids indices; store the complete indices
4 | % Double check for visited grids to avoid self-repeating
5 | for i = 1: length(arr)
6 | if J_kr(arr(i)) == 0
7 | index(arr(i)) = 0;
8 | end
9 | % What about excluding obstacles? grids == 1?
10 | % Why is the path going straight down? while heuristic value are
11 | end
12 | index = find(index);
13 | end
14 |
15 |
--------------------------------------------------------------------------------
/1-Non-Obstacles/showPath.m:
--------------------------------------------------------------------------------
1 | function showPath(map, size, path, gen, ant)
2 | figure(1);
3 | for i = 1: size*size
4 | if map(i) == 1
5 | [x_p, y_p] = ConvertXY(i, size);
6 | x1 = x_p - 0.5; y1 = y_p + 0.5;
7 | x4 = x_p - 0.5; y4 = y_p - 0.5;
8 | x2 = x_p + 0.5; y2 = y_p + 0.5;
9 | x3 = x_p + 0.5; y3 = y_p - 0.5;
10 | fill([x1, x2, x3, x4], [y1, y2, y3, y4], [0.2 0.2 0.2]);
11 | hold on;
12 | else
13 | [x_p, y_p] = ConvertXY(i, size);
14 | x1 = x_p - 0.5; y1 = y_p + 0.5;
15 | x4 = x_p - 0.5; y4 = y_p - 0.5;
16 | x2 = x_p + 0.5; y2 = y_p + 0.5;
17 | x3 = x_p + 0.5; y3 = y_p - 0.5;
18 | fill([x1, x2, x3, x4], [y1, y2, y3, y4], 'w');
19 | hold on;
20 | end
21 | end
22 | hold on;
23 | title('Map');
24 | xlabel('x-axis');
25 | ylabel('y-axis');
26 | pathRecord = path{gen, ant};
27 | ctr = length(pathRecord);
28 | robot_x = zeros(ctr, 1);
29 | robot_y = zeros(ctr, 1);
30 | for j = 1: ctr
31 | [robot_x(j), robot_y(j)] = ConvertXY(pathRecord(j), size);
32 | end
33 | plot(robot_x, robot_y);
34 | end
35 |
36 |
--------------------------------------------------------------------------------
/2-LineObstacles/ACOPathPlanning.m:
--------------------------------------------------------------------------------
1 | % Title: Ant Colony Optimisation algorithms for Robot Path Planning
2 | % Author: Yujin Li
3 | % Date: Sunday 13 March 2022
4 | clc;
5 | clear all;
6 | close all;
7 | % 1. INITIALISATION
8 | % 1.1. Environment
9 | SIZE = 10;
10 | gridMap = zeros(SIZE); % Environment configuration: 0 for clear path, 1 for obstacles
11 | gridMap(56) = 1;
12 | % gridMap(9, 4:8) = 1;
13 | % gridMap(2:9, 5) = 1;
14 | % 1.2. Parameters:
15 | % pheromone, delta pheromone: inverse of the total path length,
16 | % heuristic values, number of ants, generations of ants, Alpha: evaporation
17 | % rate, Beta: relative importance of pheromone versus distance
18 | numAnts = 30; % the number of ants in a colony
19 | numGen = 50; % the number of generations (iterations)
20 | tau = ones(SIZE*SIZE); % Pheromone Matrix Tau(r,s): amount of pheromone on
21 | % the edge from grid r to grid s. In this case, the
22 | % first column represents all the grid r and the
23 | % first row represents all the grid s, where s must
24 | % belong to J_k(r), which is a set of cities that
25 | % remain to be visited by ant k positioned on city r
26 |
27 | tau = 8.*tau; % Set the initial pheromone of all edges (r,s) as 8
28 | alpha = 0.3; % the Evaporation rate of pheromone
29 | beta = 7; % the relative importance beta
30 | home = 1; % the starting point -- home of the robot
31 | destination = SIZE*SIZE; % destination location
32 | minTourLength = inf; % the length of the shortest path
33 | bestGen = 0; % the generation that finds the shortest path
34 | bestAnt = 0; % the ant that finds the shortest path within current generation
35 | globalDelta = calcDelta(gridMap); % cost required from r to s
36 | % T_delta = table(globalDelta);
37 | % writetable(T_delta, 'globalDelta.xlsx', 'sheet', 1, 'Range', 'A1');
38 | eta = zeros(SIZE); % Heuristic value Matrix Eta(r,s), s belongs to J_k(r)
39 | eta = calcHeuristic(eta, destination); % Initialise Heuristic value
40 | % T_eta = table(eta);
41 | % writetable(T_eta, 'eta.xlsx', 'Sheet', 1, 'Range', 'A1');
42 | % edge = 1; % the size of the square grid( the length of the edge)
43 | pathStorage = cell(numGen, numAnts);
44 | pathLength = zeros(numGen, numAnts);
45 |
46 | % 2. STATE TRANSITION
47 | % 2.1 Initialisation
48 | for Gen = 1:numGen % Outter Loop: How many times ants go out and forage
49 | for Ant = 1:numAnts % Inner Loop: How many ants each time
50 | currGrid = home; % Store the current grid where the ant is located
51 | pathRecord = home; % Store the grids that the ant has walked through
52 | toBeVisited = ones(SIZE); % cities that remain to be visited by ant
53 | % k positioned on city r; 0 for visited,
54 | % 1 for to be visited
55 | toBeVisited(currGrid) = 0; % Mark the home grid as visited so it won't repeat
56 | localDelta = globalDelta;
57 | indexDelta = indexing(localDelta, currGrid, toBeVisited); % find indices of local available surrounding grids
58 | numAvailable = length(indexDelta); % the total number of the local available grids < 8
59 | counter = 1;
60 | % 2.2 The ant start finding path to destination
61 | while (currGrid ~= destination && numAvailable >= 1)
62 | % 2.2.1 Calculate the probability of choosing the certain grids based on
63 | % tau and eta
64 | stateTransProb = zeros(numAvailable, 1);
65 | for i = 1: numAvailable
66 | stateTransProb(i) = tau(currGrid, indexDelta(i)) * eta(indexDelta(i))^beta;
67 | end
68 | sumProb = sum(stateTransProb);
69 | stateTransProb = stateTransProb / sumProb;
70 | % 2.2.2 Roulette wheel selection algorithm: to choose the next grid randomly
71 | wheelProb = zeros(numAvailable, 1);
72 | wheelProb(1) = stateTransProb(1);
73 | for i = 2:numAvailable
74 | if i ~= numAvailable
75 | wheelProb(i) = wheelProb(i-1) + stateTransProb(i);
76 | else
77 | wheelProb(numAvailable) = 1;
78 | end
79 | end
80 | wheelHand = find(wheelProb >= rand, 1); % Turn the wheel and wait for the result
81 | nextGrid = indexDelta(wheelHand(1)); % Decide the next grid
82 | % 2.2.3 Store the result: the new grid, the updated length
83 | pathRecord(end + 1) = nextGrid; % Concatenate the new grid
84 | pathLength(Gen, Ant) = pathLength(Gen, Ant) + localDelta(currGrid, nextGrid);
85 | currGrid = nextGrid; % Move to the next grid
86 | % 2.2.4 Update J_k(r) and corresponding localDelta to prepare for the next move
87 | toBeVisited(currGrid) = 0;
88 | for i = 1:size(localDelta, 1)
89 | if toBeVisited(i) == 0
90 | localDelta(currGrid, i) = 0;
91 | localDelta(i, currGrid) = 0;
92 | end
93 | end
94 | indexDelta = indexing(localDelta, currGrid, toBeVisited);
95 | numAvailable = length(indexDelta);
96 | counter = counter + 1;
97 | end % the ant reaches to the destination and stop the loop
98 | % 2.3 Record the job done by the ant
99 | pathStorage{Gen, Ant} = pathRecord; % Save the path
100 | if pathRecord(end) == destination
101 | if pathLength(Gen, Ant) < minTourLength % Does the ant find a shorter path?
102 | minTourLength = pathLength(Gen, Ant); % Yes, save the new shortest path
103 | bestGen = Gen; % Remember the generation that achieved this
104 | bestAnt = Ant; % Remember the ant that achieved this
105 | end
106 | else % When the ant is not successful, offset its length in this iteration
107 | pathLength(Gen, Ant) = 0;
108 | end
109 | end % The ant finishes the forage this time
110 | % 2.4 Update the intensity of pheromone on the path
111 | deltaTau = zeros(size(tau));
112 | for i = 1: numAnts
113 | if pathLength(Gen, Ant)
114 | pathTemp = pathStorage{Gen, Ant};
115 | pathInterval = length(pathTemp) - 1;
116 | for j = 1: pathInterval
117 | deltaTau(pathTemp(j), pathTemp(j + 1)) = 1 / pathLength(Gen, Ant);
118 | deltaTau(pathTemp(j + 1), pathTemp(j)) = 1 / pathLength(Gen, Ant);
119 | end
120 | end
121 | end
122 | tau = (1 - alpha) .* tau + deltaTau; % pheromone evaporation rule
123 | end % All the ants in this generation finished forage; restart a new generation now
124 |
125 | % 3. VISUALISATION
126 | showPath(gridMap,SIZE, pathStorage, bestGen, bestAnt);
127 | showLength(pathLength);
128 |
--------------------------------------------------------------------------------
/2-LineObstacles/ConvertXY.m:
--------------------------------------------------------------------------------
1 | function [x, y] = ConvertXY(gridNum, rowMap) % Extract x coordinate from the serial number of the location
2 | x = ceil(gridNum / rowMap) - 0.5;
3 | y = rowMap - mod(gridNum, rowMap) + 0.5;
4 | if y == rowMap + 0.5
5 | y = 0.5;
6 | end
7 | end
8 |
9 |
--------------------------------------------------------------------------------
/2-LineObstacles/Iterations.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlyEugeneLi/ACO-RobotPathPlanning-MATLAB/cb5c0c694d91860b83171b91530f74c3ea0f1ac4/2-LineObstacles/Iterations.jpg
--------------------------------------------------------------------------------
/2-LineObstacles/Log.md:
--------------------------------------------------------------------------------
1 | This is the 2nd version.
2 | **Date: 20 March 2022
3 |
4 | # Actions Log
5 |
6 | At this stage, the main task is to **test different scenarios** and see if there is any bugs prompt out.
7 |
8 | Then, modify the programme to improve the performance in terms of **accuracy, stability and response speed**.
9 |
10 | Lastly, prepare **presentation** to introduce algorithms used in detail at Monday's meeting.
11 |
12 | ## 1. Obstacles
13 |
14 | ### Obstacles added.
15 | ```
16 | gridMap(2:9, 5) = 1;
17 | ```
18 | * Think about:
19 |
20 | * How to find the best solution by hand-calculation and compare with the result from the programme when the map gets more and more complex?
21 | * TBC...
22 |
23 | ## 2. Δ(r, s) array generation
24 |
25 | ### 🐭 Bug occurred:
26 |
27 | * Can't detect obstacle at gridMap(88) and some surrounding grids when
28 | ```
29 | gridMap(9, 4:8) = 1;
30 | gridMap(4:9, 9) = 1;
31 | ```
32 | * Check data detail in file [globalDelta_Bug.xlsx](../1-Non-Obstacles/globalDelta_Bug.xlsx)
33 | * Original code in [delta_r2s.m](../1-Non-Obstacles/delta_r2s.m)
34 | ```
35 | function D = delta_r2s(arr) % delta_(r,s): cost from grid r to grid s
36 | % r and s must be next to each other ssss
37 | row = size(arr, 1); % the number of rows of the array
38 | column = size(arr, 2);
39 | D = zeros(row*column); % initialise the delta_(r,s) matrix
40 | % Outer Loop
41 | for i = 1:row
42 | for j = 1:column % Outter Loop: Traverse all the grids to set their cost
43 | % of traveling to the local surrouding grids
44 | if arr(i, j) == 0 % grid r must not be a obstacle
45 |
46 | % Inner Loop
47 | for x = 1:row
48 | for y = 1:column % Inner Loop: find the surrounding available
49 | % grids s and return the cost value
50 | % (distance) to the exact variable in
51 | % the matrix
52 | if arr(x, y) == 0 % the surrounding grid must be clear
53 | rel_x = abs(i - x); % relative distance between grid r and s on x direction
54 | rel_y = abs(j - y); % relative distance between grid r and s on y direction
55 | if rel_x + rel_y == 1 || (rel_x == 1 && rel_y == 1)
56 | % When this grid is one of the adjacent
57 | % grids in 8 directions
58 | D((i-1)*column + j, (x-1)*column + y) = sqrt(rel_x^2 + rel_y^2);
59 | % D(r, s), r and s are indices of one-dimensional matrix
60 | % Return relative distance between r and s
61 | end
62 | end
63 | end
64 | end
65 | end
66 | end
67 | end
68 |
69 | end
70 | ```
71 |
72 | ### ✔️ Solution:
73 |
74 | * Updated the generation process [calcDelta.m](calcDelta.m)
75 |
76 | ```
77 | function D = calcDelta(arr)
78 | row = size(arr, 1); % the number of rows of the array
79 | column = size(arr, 2);
80 | D = zeros(row*column); % initialise the delta_(r,s) matrix
81 | for i = 1: row*column
82 | if arr(i) == 0
83 | for j = 1: row*column
84 | if arr(j) == 0 && (abs(i - j) == 11 || abs(i - j) == 10 || abs(i - j) == 9 || abs(i - j) == 1)
85 | [x1, y1] = ConvertXY(j, row);
86 | [x2, y2] = ConvertXY(i, row);
87 | D(i, j) = sqrt((x1 - x2)^2 + (y1 - y2)^2);
88 | D(j, i) = sqrt((x1 - x2)^2 + (y1 - y2)^2);
89 | end
90 | end
91 | end
92 | end
93 |
94 | end
95 | ```
96 |
97 | ## 3. Modify pheromone evaporation rate Δτ
98 |
99 | Changing _Δτ_ can improve the accuracy, which means the higher chance of returning the expected answer.
100 |
101 |
102 |
103 | ### 🐭 Bug: Path length converging at the highest level
104 |
105 | The length-iteration diagram was expected to show the convergence at the lowest value instead of the greatest value.
106 |
107 | 
108 | |:--:|
109 | | *Robot path records* |
110 |
111 | 
112 | |:--:|
113 | | *Length-Iteration diagram* |
114 |
115 | ### 📆 21 March 2022 Update
116 |
117 | * Pheromone update rules mis-coded ❎
118 | ```
119 | % 2.4 Update the intensity of pheromone on the path
120 | deltaTau = zeros(size(tau));
121 | for i = 1: numAnts
122 | if pathLength(Gen, Ant)
123 | pathTemp = pathStorage{Gen, Ant};
124 | pathInterval = length(pathTemp) - 1;
125 | for j = 1: pathInterval
126 | deltaTau(pathTemp(j), pathTemp(j + 1)) = 1 / pathLength(Gen, Ant);
127 | deltaTau(pathTemp(j + 1), pathTemp(j)) = 1 / pathLength(Gen, Ant);
128 | end
129 | end
130 | end
131 | tau = (1 - alpha) .* tau + deltaTau; % pheromone evaporation rule
132 | ```
133 | #### :hammer: Debug Attempt:
134 |
135 | the _pathLength(Gen, **Ant**)_ should be _pathLength(Gen, **i**)_
136 |
137 | :black_nib: Thougth: If it followed the first code, it would only update the pheromone based on **the last ant's path**.
138 |
139 | * Code:
140 | ```
141 | % 2.4 Update the intensity of pheromone on the path
142 | deltaTau = zeros(size(tau));
143 | for i = 1: numAnts
144 | if pathLength(Gen, i)
145 | pathTemp = pathStorage{Gen, i};
146 | for j = 1: size(pathTemp)
147 | deltaTau(pathTemp(j)) = deltaTau(pathTemp(j)) + 1 / pathLength(Gen, i);
148 | end
149 | end
150 | end
151 | tau = (1 - alpha) .* tau + deltaTau; % pheromone evaporation rule
152 | ```
153 | * Resulte: Still not converging to the smallest value
154 | * Change the Pheromone update rule τ(r, s), using 2D array
155 |
156 | 
157 | |:--:|
158 | | *Robot path records: changed the pheromone update rule* |
159 |
160 | 
161 | |:--:|
162 | | *Length-Iteration diagram: changed the pheromone update rule* |
163 |
164 | * Change the relative importance of pheromone = 4
165 | ```
166 | % Original
167 | stateTransProb(i) = tau(indexDelta(i)) * eta(indexDelta(i))^beta;
168 |
169 | % NEW
170 | stateTransProb(i) = tau(indexDelta(i))^4 * eta(indexDelta(i))^beta;
171 | ```
172 | 
173 | |:--:|
174 | | *Robot path records: changed the pheromone update rule* |
175 |
176 | 
177 | |:--:|
178 | | *Length-Iteration diagram: changed the pheromone update rule* |
179 |
--------------------------------------------------------------------------------
/2-LineObstacles/Results/Length-Iteration__relativeImportance4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlyEugeneLi/ACO-RobotPathPlanning-MATLAB/cb5c0c694d91860b83171b91530f74c3ea0f1ac4/2-LineObstacles/Results/Length-Iteration__relativeImportance4.jpg
--------------------------------------------------------------------------------
/2-LineObstacles/Results/Length-Iteration_newPheromoneupdate.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlyEugeneLi/ACO-RobotPathPlanning-MATLAB/cb5c0c694d91860b83171b91530f74c3ea0f1ac4/2-LineObstacles/Results/Length-Iteration_newPheromoneupdate.jpg
--------------------------------------------------------------------------------
/2-LineObstacles/Results/robotPath_newPheromoneupdate.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlyEugeneLi/ACO-RobotPathPlanning-MATLAB/cb5c0c694d91860b83171b91530f74c3ea0f1ac4/2-LineObstacles/Results/robotPath_newPheromoneupdate.jpg
--------------------------------------------------------------------------------
/2-LineObstacles/Results/robotPath_relativeImportance4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlyEugeneLi/ACO-RobotPathPlanning-MATLAB/cb5c0c694d91860b83171b91530f74c3ea0f1ac4/2-LineObstacles/Results/robotPath_relativeImportance4.jpg
--------------------------------------------------------------------------------
/2-LineObstacles/calcDelta.m:
--------------------------------------------------------------------------------
1 | function D = calcDelta(arr)
2 | row = size(arr, 1); % the number of rows of the array
3 | column = size(arr, 2);
4 | D = zeros(row*column); % initialise the delta_(r,s) matrix
5 | for i = 1: row*column
6 | if arr(i) == 0
7 | for j = 1: row*column
8 | if arr(j) == 0 && (abs(i - j) == 11 || abs(i - j) == 10 || abs(i - j) == 9 || abs(i - j) == 1)
9 | [x1, y1] = ConvertXY(j, row);
10 | [x2, y2] = ConvertXY(i, row);
11 | D(i, j) = sqrt((x1 - x2)^2 + (y1 - y2)^2);
12 | D(j, i) = sqrt((x1 - x2)^2 + (y1 - y2)^2);
13 | end
14 | end
15 | end
16 | end
17 |
18 | end
19 |
20 |
--------------------------------------------------------------------------------
/2-LineObstacles/calcHeuristic.m:
--------------------------------------------------------------------------------
1 | function Eta = calcHeuristic(arr, grid)
2 | dim1 = size(arr, 1);
3 | dim2 = size(arr, 1) * size(arr, 1);
4 | for i = 1:dim2
5 | [desti_x, desti_y] = ConvertXY(grid, dim1);
6 | [x, y] = ConvertXY(i, dim1);
7 | distance = sqrt((x - desti_x)^2 + (y - desti_y)^2);
8 | if i ~= grid
9 | arr(i) = 1 / distance;
10 | else
11 | arr(grid) = 100;
12 | end
13 | end
14 | Eta = arr;
15 | end
16 |
17 |
--------------------------------------------------------------------------------
/2-LineObstacles/indexing.m:
--------------------------------------------------------------------------------
1 | function index = indexing(delta, grid, J_kr) % Return the indices of available grids
2 | index = delta(grid, :); % Store the cost required to the next gird
3 | arr = find(index); % Scope down available adjacent grids indices; store the complete indices
4 | % Double check for visited grids to avoid self-repeating
5 | for i = 1: length(arr)
6 | if J_kr(arr(i)) == 0
7 | index(arr(i)) = 0;
8 | end
9 | % What about excluding obstacles? grids == 1?
10 | % Why is the path going straight down? while heuristic value are
11 | end
12 | index = find(index);
13 | end
14 |
15 |
--------------------------------------------------------------------------------
/2-LineObstacles/robotPathRecords.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlyEugeneLi/ACO-RobotPathPlanning-MATLAB/cb5c0c694d91860b83171b91530f74c3ea0f1ac4/2-LineObstacles/robotPathRecords.jpg
--------------------------------------------------------------------------------
/2-LineObstacles/showLength.m:
--------------------------------------------------------------------------------
1 | function showLength(arr)
2 | figure(2)
3 |
4 | row = size(arr, 1);
5 | column = size(arr, 2);
6 | minLength = zeros(row, 1);
7 | for i = 1: row
8 | arrRows = arr(i, :);
9 | index = arrRows ~= 0;
10 | arrRows = arrRows(index);
11 | minLength(i) = min(arrRows);
12 | end
13 | plot(minLength);
14 | hold on
15 | grid on
16 | title('Path Length Changes During Iterations');
17 | xlabel('Iteration');
18 | ylabel('Minimum Path Length');
19 | end
20 |
21 |
--------------------------------------------------------------------------------
/2-LineObstacles/showPath.m:
--------------------------------------------------------------------------------
1 | function showPath(map, size, path, gen, ant)
2 | figure(1);
3 | for i = 1: size*size
4 | if map(i) == 1
5 | [x_p, y_p] = ConvertXY(i, size);
6 | x1 = x_p - 0.5; y1 = y_p + 0.5;
7 | x4 = x_p - 0.5; y4 = y_p - 0.5;
8 | x2 = x_p + 0.5; y2 = y_p + 0.5;
9 | x3 = x_p + 0.5; y3 = y_p - 0.5;
10 | fill([x1, x2, x3, x4], [y1, y2, y3, y4], [0.2 0.2 0.2]);
11 | hold on;
12 | else
13 | [x_p, y_p] = ConvertXY(i, size);
14 | x1 = x_p - 0.5; y1 = y_p + 0.5;
15 | x4 = x_p - 0.5; y4 = y_p - 0.5;
16 | x2 = x_p + 0.5; y2 = y_p + 0.5;
17 | x3 = x_p + 0.5; y3 = y_p - 0.5;
18 | fill([x1, x2, x3, x4], [y1, y2, y3, y4], 'w');
19 | hold on;
20 | end
21 | end
22 | hold on;
23 | title('Map');
24 | xlabel('x-axis');
25 | ylabel('y-axis');
26 | pathRecord = path{gen, ant};
27 | ctr = length(pathRecord);
28 | robot_x = zeros(ctr, 1);
29 | robot_y = zeros(ctr, 1);
30 | for j = 1: ctr
31 | [robot_x(j), robot_y(j)] = ConvertXY(pathRecord(j), size);
32 | end
33 | plot(robot_x, robot_y);
34 | end
35 |
36 |
--------------------------------------------------------------------------------
/3 - Convergence/Log.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | This week, I should finalise the experiment model.
4 |
5 | ## 🔖 To-do list updated on [25-03-2022]
6 |
7 | * Learn from the working example code
8 | * ✔️ Resolve the flawed condition on line 8 in ```calcDelta``` function
9 | * ✔️Inspect pheromone update process and foraging process
10 | * ✔️Would be helpful to check ```calcDelta``` ```ConvertXY``` ```tau``` ```deltaTau``` ```pathRecord``` ```globalDelta``` ```pathLength```
11 | * ✔️ Should expect the converge result in the end
12 | * Analyse the map size, iterations, number of ants, relative importance, pheromone matrix to solve the convergence issue
13 | * Maybe it is not supposed to converge at the minimal value? just close
14 |
15 | ## 📍 [Unreleased]
16 |
17 | ### Parameters modifications
18 |
19 | * Q - pheromone intensity coefficient can be considered later
20 |
21 | ### Visualisation
22 |
23 | * Pheromone intensity map - distinguish each level with a set of colours
24 | * Maybe show it changing along the iterations
25 |
26 | ### Compare 'Without pheromone' & 'With Pheromone'
27 |
28 | * 📉 Shown difference on line chart:
29 | * Pure lucky & guided by colony's trend
30 |
31 | ## 📖 Week 8 Meeting [21-03-2022] - Outlines
32 | * The ants should converge to the optimal solution in the end.
33 | * Try visualise the process: from arbitrarily-generated path to the pheromone-guided-generated path.
34 | * Try visualise pheromone change progress
35 | * Compare results from different sets of parameters: the number of ants, the number of iterations and pheromone evaporation rate.
36 | * Mann-whitney test
37 | * Imitate the excellent example sent by Dr Castellani
38 |
39 | ## 🆕 Update [25/03/2022]
40 |
41 | Focused on pheromone update code.
42 |
43 | ### 🔴 Issues
44 |
45 | * ✔️ Collision: In rare cases, robot still collides with obstacles.
46 | * Instead of collision, it is actually flying over to distanced grids because of wrong cost measure **δ** set up.
47 |
48 |
49 | |:--:|
50 | | *Figure 1* |
51 |
52 | When I changed the code to... (Though that's not the key point)
53 | ```
54 | tau = ones(SIZE);
55 | tau = 10.*tau; % Set the initial pheromone of all edges (r,s) as 8
56 | alpha = 0.4; % the Evaporation rate of pheromone
57 | ```
58 |
59 | * Pheromone matrix **τ** updates abnormally
60 | * Only grid 1 was updated when other grids in **Δτ** remain zero
61 |
62 |
63 | ### 👨🔧 Actions
64 |
65 | * Checked ``` tau ``` and ``` deltaTau ``` data
66 | * Only grid 1 in ``` deltaTau ``` has value; Grid 1 in ``` tau ``` was 16.2298
67 | * Why is only grid 1 updated while the entire path should be passed new values?
68 |
69 |
70 | * Changed line 118 from ``` for j = 1: size(pathTemp)``` to ``` for j = 1: length(pathTemp) ```
71 | * pheromone matrix **τ** seems normal now
72 |
73 | * Collision issue
74 | * Checked ```pathRecord``` to see the path trail and ```globalDelta``` to see the available grids
75 | * Checked ```calDelta``` function: the condition logic is flawe
76 |
77 | calDelta function line 8:
78 | ```
79 | if arr(j) == 0 && (abs(i - j) == 11 || abs(i - j) == 10 || abs(i - j) == 9 || abs(i - j) == 1)
80 | ```
81 | ❗ abs(i - j) == 10 and abs(i - j) == would recognise girds at the other end of the same column by mistake.
82 |
83 | ## 🆕 Update [26-03-2022]
84 |
85 | Focused on fixing the **condition** of scoping down available surrounding grids in cost measure **δ(r, s)** function
86 |
87 | ### 🔴 Issues
88 |
89 | * Fluctuation occurs occasionally
90 |
91 | Parameters setting
92 | ```
93 | SIZE = 10;
94 | gridMap = zeros(SIZE); % Environment configuration: 0 for clear path, 1 for obstacles
95 | gridMap(5, 2:9) = 1;
96 | gridMap(9, 4:8) = 1;
97 | gridMap(2:9, 5) = 1;
98 | numAnts = 5; % the number of ants in a colony
99 | numGen = 200; % the number of generations (iterations)
100 | ```
101 |
102 |
103 | |:--:|
104 | | *Figure 2* |
105 |
106 |
107 | |:--:|
108 | | *Figure 3* |
109 |
110 |
111 | When ```numAnts = 10; numGen = 200; ```:
112 |
113 | |:--:|
114 | | *Figure 4* |
115 |
116 | * Not converge to the minimal path length when increasing the iterations
117 |
118 | ```numAnts = 50; numGen = 100; alpha = 0.4```
119 | 
120 |
121 | ```numAnts = 50; numGen = 200; ```
122 | 
123 |
124 | * Fluctuate when relative importance of pheromone are less
125 | Could not converge
126 | ```
127 | numAnts = 10; numGen = 100; alpha = 0.4; beta = 7;
128 | ...
129 | stateTransProb(i) = tau(indexDelta(i)) * eta(indexDelta(i))^beta;
130 | ```
131 | * Potential sources:
132 | Pheromone evaporation rule;
133 |
134 |
135 | ### 👨🔧 Actions
136 |
137 | * Modified conditions (line 8) of recognising surrounding grids in function ```calcDelta(arr)```
138 | * Before update:
139 | ```
140 | if arr(j) == 0 && (abs(i - j) == 11 || abs(i - j) == 10 || abs(i - j) == 9 || abs(i - j) == 1)
141 | ```
142 | Such condition will not only select out surrounding grids, but also grids on the both end of each column, causing issues of fake collision (or flying to the other end) shown in _Figure 1_ in **Issue [25-03-2022]** section.
143 |
144 | * After update:
145 | ```
146 | if arr(j) == 0 && (abs(i - j) == 11 || abs(i - j) == 10 || abs(i - j) == 9 || abs(i - j) == 1)
147 | [xi, yi] = ConvertXY(i, row);
148 | [xj, yj] = ConvertXY(j, row);
149 | dis = sqrt((xi - xj)^2 + (yi - yj)^2); % Check the distance
150 | if dis <= sqrt(2) % Make sure it's surrouding the current grid
151 | D(i, j) = dis; % sqrt((x1 - x2)^2 + (y1 - y2)^2);
152 | D(j, i) = dis; % sqrt((x1 - x2)^2 + (y1 - y2)^2);
153 | end
154 | end
155 | ```
156 | * Updated results
157 |
158 | Surprisingly, the convergence issue has been solved after solving the fake collision issue.
159 |
160 | ``` numAnts = 20; numGen = 50;```
161 |
162 | |:--:|
163 | | *Figure 5* |
164 |
165 |
166 | |:--:|
167 | | *Figure 6* |
168 |
169 | ``` numAnts = 50; numGen = 100; ```
170 |
171 | |:--:|
172 | | *Figure 7* |
173 |
174 | * Changed relative importance
175 |
176 | Works better
177 | ```
178 | numAnts = 10; numGen = 100; alpha = 0.4; beta = 7;
179 | ...
180 | stateTransProb(i) = tau(indexDelta(i))^5 * eta(indexDelta(i))^beta;
181 | ```
182 | Result:
183 |
184 |
185 | |:--:|
186 | | *Figure 8* |
187 |
188 | Could not converge
189 | ```
190 | numAnts = 10; numGen = 100; alpha = 0.4; beta = 7;
191 | ...
192 | stateTransProb(i) = tau(indexDelta(i)) * eta(indexDelta(i))^beta;
193 | ```
194 | Result:
195 |
196 |
197 | |:--:|
198 | | *Figure 9* |
199 |
200 | * Modified relative importance making pheromone more important than heuristic value
201 | * It can converge now
202 | * How does the example work with heuristic value more important than pheromone??
203 |
204 |
205 | ### Questions
206 |
207 | * 报告花多少时间
208 | * 有些情况会出问题:我代码写的和别人的不太一样,得到的结果有出入,但符合预期,要怎么办
209 | * 怎样写好报告
210 | * 本科毕设需要提出创新的点吗?从什么角度入手比较好
211 |
--------------------------------------------------------------------------------
/4 - Final Stage/Log.md:
--------------------------------------------------------------------------------
1 | # ChangeLog
2 |
3 | At this stage, the main focus is on thinking, questioning, analysing and concluding the work that has been done.
4 |
5 | ## Report Writing
6 |
7 | ### General instruction
8 |
9 | * From the [blog](https://academia.stackexchange.com/questions/76843/when-writing-a-paper-whats-the-difference-between-contributions-and-objectives)
10 |
11 | "Usually, the scheme of a scientific study has a hourglass shape scheme, from wide, to narrow, and wide again.
12 |
13 | In the first wide, we use the introduction to describe the general topography and bring focus to a particular problem. Then we narrow down to describe how our experiment is designed, data are collected, analysis is done, etc.
14 |
15 | When results are ready, we interpret them, and then again widen up the scope to talk about implications, applications, and recommendations in the Discussion section.
16 |
17 | In my opinion, objectives are a list of actions to perform, or questions to answer so that you can complete the narrow part of the study scheme. Contributions are a list of applications or significance to other researchers that brought about by your work, and they are perhaps more fitting in the second wider part of the study scheme."
18 |
19 |
20 | ## Meeting with Feiying
21 |
22 | **Takeaways:**
23 |
24 | * 精英策略
25 | * Error code 误差曲线
26 | * 准确率
27 | * 用了多少次迭代
28 | * 讨论
29 | * 为什么用这个方法好 - 如何更有效率,更完善 - 探讨指标
30 | * 为什么这样会变好 - 不消耗计算负担的参数,提升性能 - 有什么参数可以实现这个
31 | * 以辩证角度评论文献综述,逻辑连贯要支撑我为什么要做这个项目
32 | * 思考
33 | * 一定要收敛吗?这是一个概率选择的过程,总会出现偏差。为什么会出现波动?说明信息素和启发素浓度不够?
34 | * 每次迭代取得最优解的蚂蚁的数量占比的变化有没有分析价值?
35 | * 能否展示每次迭代所有蚂蚁的路径在同一个地图并随着迭代次数的变化情况来看信息素有没有发挥的作用?
36 | * 改变了相对的重要性参数
37 |
38 | ## 📍 [Unreleased]
39 |
40 | ### 🚩 Elitism / Elitist Preservation
41 |
42 | Proposed by Kenneth A. De Jong from his Ph.D dissertation on Genetic Algorithms
43 |
44 | #### Definition
45 |
46 | maintain the best solution found over time before selection
47 |
48 | #### Potential Application
49 |
50 | Apply it to ACO ensuring that the algorithm converge at the best solution
51 |
52 | Refer to this [blog about Elitist Preservation](https://www.cnblogs.com/devilmaycry812839668/p/6445762.html) for the details of the method
53 |
54 | [Python example](https://dothinking.github.io/2018-10-27-%E9%81%97%E4%BC%A0%E7%AE%97%E6%B3%95%EF%BC%9A%E6%94%B9%E8%BF%9B%E6%96%B9%E5%90%91%E4%B9%8B%E7%B2%BE%E8%8B%B1%E7%AD%96%E7%95%A5/#:~:text=%E8%87%AA%E9%80%82%E5%BA%94%E7%AD%96%E7%95%A5-,%E7%B2%BE%E8%8B%B1%E4%BF%9D%E7%95%99%E7%AD%96%E7%95%A5,%E4%BF%9D%E7%95%99(Elitist%20Preservation)%20%E7%AD%96%E7%95%A5%E3%80%82)
55 |
56 | ## 🚩
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
15 | This report presents the visualisations and analysis of using ACO to address NP-hard complexity within Robot Path Planning problems.
16 |
17 | Explore the docs »
18 |
19 |
20 | View Demo
21 | ·
22 | Report Bug
23 | ·
24 | Request Feature
25 |