深圳幻海软件技术有限公司 欢迎您!

遗传算法之路径规划matlab代码(栅格地图)含详细注释

2023-03-31

遗传算法本人在另一篇博文中已经有记载,本次将遗传算法用于路径规划的代码记录于此,用于大家一起学习一起进步,如果有用,欢迎点赞。1.基于遗传算法的栅格法机器人路径规划main.m%基于遗传算法的栅格法机器人路径规划%jubobolv369clc;clear;%输入数据,即栅格地图.20行20列Grid

遗传算法本人在另一篇博文中已经有记载,本次将遗传算法用于路径规划的代码记录于此,用于大家一起学习 一起进步,如果有用,欢迎点赞。

1.基于遗传算法的栅格法机器人路径规划main.m

  1. % 基于遗传算法的栅格法机器人路径规划
  2. %jubobolv369
  3. clc;
  4. clear;
  5. % 输入数据,即栅格地图.2020
  6. Grid= [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
  7. 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
  8. 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
  9. 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
  10. 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
  11. 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
  12. 0 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
  13. 0 0 0 0 0 0 1 1 1 0 1 0 1 1 0 0 0 0 0 0;
  14. 0 1 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 0;
  15. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
  16. 0 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 0 0 0 0;
  17. 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0;
  18. 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 0;
  19. 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0;
  20. 0 0 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0;
  21. 0 0 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0;
  22. 0 0 0 0 0 0 1 1 1 0 1 0 0 0 0 0 0 1 1 0;
  23. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0;
  24. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0;
  25. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0];
  26. start_num = 0; % 起点编号
  27. end_num = 399; % 终点序号
  28. NP = 200; % 种群数量
  29. max_gen = 50; % 最大进化代数
  30. pc = 0.8; % 交叉概率
  31. pm = 0.2; % 变异概率
  32. a = 1; % 路径长度比重
  33. b = 7; % 路径顺滑度比重
  34. z = 1;
  35. new_pop1 = {}; % 元胞数组,存放路径
  36. [y, x] = size(Grid);
  37. % 起点所在列(从左到右编号1.2.3...)
  38. start_column = mod(start_num, x) + 1;
  39. % 起点所在行(从上到下编号行1.2.3...)
  40. start_row = fix(start_num / x) + 1; %Y = fix(X) 将 X 的每个元素朝零方向四舍五入为最近的整数
  41. % 终点所在列、行
  42. end_column = mod(end_num, x) + 1;
  43. end_row = fix(end_num / x) + 1;
  44. %% 种群初始化step1,必经节点,从起始点所在行开始往上,在每行中挑选一个自由栅格,构成必经节点
  45. pass_num = end_row - start_row + 1; %每条路径的节点个数
  46. pop = zeros(NP, pass_num);%生成种群数量*节点个数的矩阵,用于存放每个个体的路径
  47. for i = 1 : NP %每个个体(每行)循环操作:
  48. pop(i, 1) = start_num; %每行第一列都为起点(存入起点的编号)
  49. j = 1;
  50. % 此for循环用于寻找除去起点和终点所在行以外每行中的自由栅格
  51. for row_i = start_row+1 : end_row-1 %栅格的第二行到倒数第二行循环
  52. j = j + 1;
  53. % 存放栅格里当前行中的自由栅格序号
  54. free = [];
  55. for column_i = 1 : x %从第一列到第二十列中
  56. % 栅格对应的序号
  57. num = (column_i - 1) + (row_i - 1) * x;
  58. % 如果该栅格为非障碍物
  59. if Grid(row_i, column_i) == 0
  60. % 把此栅格的编号加入free矩阵中
  61. free = [free num];
  62. end
  63. end % 栅格一行里的自由栅格查询结束,自由栅格的编号存在了向量中
  64. free_num = length(free);
  65. % 产生小于等于本行自由栅格数量的一个随机整数
  66. index = randi(free_num); %X = randi(imax) 返回一个介于 1 和 imax 之间的伪随机整数标量。
  67. % 将栅格中当前行的自由栅格矩阵free中第index个栅格编号作为当前种群的第j个节点
  68. pop(i, j) = free(index);
  69. end %该个体的每一行的路径节点产生完成,存入了pop的第i行中
  70. pop(i, end) = end_num; %pop的每行第最后一列都为终点(存入终点的编号)
  71. %% 种群初始化step2将上述必经节点联结成无间断路径
  72. single_new_pop = generate_continuous_path(pop(i, :), Grid, x);
  73. if ~isempty(single_new_pop)%如果这一行种群的路径不是空的,将这行路径存入元胞数组中。
  74. new_pop1(z, 1) = {single_new_pop};
  75. z = z + 1;
  76. end
  77. end
  78. %% 计算初始化种群的适应度
  79. % 计算路径长度
  80. path_value = cal_path_value(new_pop1, x);
  81. % 计算路径平滑度
  82. path_smooth = cal_path_smooth(new_pop1, x);
  83. fit_value = a .* path_value .^ -1 + b .* path_smooth .^ -1;
  84. mean_path_value = zeros(1, max_gen);
  85. min_path_value = zeros(1, max_gen);
  86. %% 循环迭代操作
  87. for i = 1 : max_gen
  88. % 选择操作
  89. new_pop2 = selection(new_pop1, fit_value);
  90. % 交叉操作
  91. new_pop2 = crossover(new_pop2, pc);
  92. % 变异操作
  93. new_pop2 = mutation(new_pop2, pm, Grid, x);
  94. % 更新种群
  95. new_pop1 = new_pop2;
  96. % 计算适应度值
  97. % 计算路径长度
  98. path_value = cal_path_value(new_pop1, x)
  99. % 计算路径平滑度
  100. path_smooth = cal_path_smooth(new_pop1, x)
  101. fit_value = a .* path_value .^ -1 + b .* path_smooth .^ -1
  102. mean_path_value(1, i) = mean(path_value);
  103. [~, m] = max(fit_value);
  104. min_path_value(1, i) = path_value(1, m);
  105. end
  106. %% 画每次迭代平均路径长度和最优路径长度图
  107. figure(1)
  108. plot(1:max_gen, mean_path_value, 'r')
  109. hold on;
  110. title(['a = ', num2str(a)', ',b = ',num2str(b)','的优化曲线图']);
  111. xlabel('迭代次数');
  112. ylabel('路径长度');
  113. plot(1:max_gen, min_path_value, 'b')
  114. legend('平均路径长度', '最优路径长度');
  115. min_path_value(1, end)
  116. % 在地图上画路径
  117. [~, min_index] = max(fit_value);
  118. min_path = new_pop1{min_index, 1};
  119. figure(2)
  120. hold on;
  121. title(['a = ', num2str(a)', ',b = ',num2str(b)','遗传算法机器人运动轨迹']);
  122. xlabel('坐标x');
  123. ylabel('坐标y');
  124. DrawMap(Grid);
  125. [~, min_path_num] = size(min_path);
  126. for i = 1:min_path_num
  127. % 路径点所在列(从左到右编号1.2.3...)
  128. x_min_path(1, i) = mod(min_path(1, i), x) + 1;
  129. % 路径点所在行(从上到下编号行1.2.3...)
  130. y_min_path(1, i) = fix(min_path(1, i) / x) + 1;
  131. end
  132. hold on;
  133. plot(x_min_path, y_min_path, 'r')

2.将必经节点联结成无间断路径,如果结点间不连续,则插入节点使其连续generate_continuous_path.m

  1. % 将必经节点联结成无间断路径,如果结点间不连续,则插入节点使其连续。
  2. %jubobolv369
  3. function [single_new_pop] = generate_continuous_path(single_pop, Grid, x)
  4. i = 1;
  5. single_new_pop = single_pop; %传入的某行的初始路径,有20个路径节点
  6. [~, single_path_num] = size(single_new_pop);
  7. %遍历该行的所有节点,使其连续
  8. while i ~= single_path_num
  9. %%定位第i、i+1个节点的坐标
  10. % 路径中第i个栅格在地图的列(从左到右编号1.2.3...)
  11. column_now = mod(single_new_pop(1, i), x) + 1;
  12. % 路径中第i个栅格在地图的行(从上到下编号行1.2.3...)
  13. row_now = fix(single_new_pop(1, i) / x) + 1;
  14. % 路径中第i+1个栅格在地图的列、行
  15. column_next = mod(single_new_pop(1, i + 1), x) + 1;
  16. row_next = fix(single_new_pop(1, i + 1) / x) + 1;
  17. % 初始化最大迭代次数
  18. max_iteration = 0;
  19. %% 判断点i和i+1是否连续,若不连续插入值(如果前后两节点的X坐标与Y坐标的差中较大值不等于1,说明不连续)
  20. while max(abs(column_next - column_now), abs(row_next - row_now)) ~= 1
  21. %取两节点的中点作为插入点,见forGA_word.xls-sheet1
  22. %插入点的横坐标 x_insert,纵坐标 y_insert
  23. x_insert = floor((column_next + column_now) / 2);%Y = floor(X) 将 X 的每个元素四舍五入到小于或等于该元素的最接近整数。
  24. y_insert = floor((row_next + row_now) / 2);
  25. % 插入栅格为自由栅格
  26. if Grid(y_insert, x_insert) == 0
  27. % 插入的栅格序号
  28. num_insert = (x_insert - 1) + (y_insert - 1) * x;
  29. % 插入新序号(将当前的栅格序号中间插入一个新栅格序号 其他保持不变)
  30. single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
  31. % 插入栅格为障碍物栅格
  32. else
  33. % 往左走(如果当前待插入格(障碍物格)的左邻格不是障碍物 且 左邻格不是当前研究的两个格中任意一个)
  34. if Grid(y_insert, x_insert - 1) == 0 && ((x_insert - 2) + (y_insert - 1) * x ~= single_new_pop(1, i)) && ((x_insert - 2) + (y_insert - 1) * x ~= single_new_pop(1, i+1))
  35. x_insert = x_insert - 1;
  36. % 栅格序号
  37. num_insert = (x_insert - 1) + (y_insert - 1) * x;
  38. % 插入新序号
  39. single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
  40. % 往右走 (如果当前待插入格(障碍物格)的右邻格不是障碍物 且 右邻格不是当前研究的两个格中任意一个)
  41. elseif Grid(y_insert, x_insert + 1) == 0 && (x_insert + (y_insert - 1) * x ~= single_new_pop(1, i)) && (x_insert + (y_insert - 1) * x ~= single_new_pop(1, i+1))
  42. x_insert = x_insert + 1;
  43. % 栅格序号
  44. num_insert = (x_insert - 1) + (y_insert - 1) * x;
  45. % 插入新序号
  46. single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
  47. % 向上走
  48. elseif Grid(y_insert + 1, x_insert) == 0 && ((x_insert - 1) + y_insert * x ~= single_new_pop(1, i)) && ((x_insert - 1) + y_insert * x ~= single_new_pop(1, i+1))
  49. y_insert = y_insert + 1;
  50. % 栅格序号
  51. num_insert = (x_insert - 1) + (y_insert - 1) * x;
  52. % 插入新序号
  53. single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
  54. % 向下走
  55. elseif Grid(y_insert - 1, x_insert) == 0 && ((x_insert - 1) + (y_insert - 2) * x ~= single_new_pop(1, i)) && ((x_insert - 1) + (y_insert-2) * x ~= single_new_pop(1, i+1))
  56. y_insert = y_insert - 1;
  57. % 栅格序号
  58. num_insert = (x_insert - 1) + (y_insert - 1) * x;
  59. % 插入新序号
  60. single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
  61. % 如果各方向都无法插入则舍去此路径
  62. else
  63. %break_pop = single_new_pop
  64. single_new_pop = [];
  65. break
  66. end
  67. end
  68. column_next = x_insert;
  69. row_next = y_insert;
  70. max_iteration = max_iteration + 1;
  71. %如果可以不断的增加新节点,但增加次数超过20000次,则舍弃此路径
  72. if max_iteration > 20000
  73. single_new_pop = [];
  74. break
  75. end
  76. end
  77. if isempty(single_new_pop)
  78. break
  79. end
  80. [~, single_path_num] = size(single_new_pop);
  81. i = i + 1;
  82. end

3.计算路径长度函数cal_path_value.m

  1. %% 计算路径长度函数
  2. %jubobolv369
  3. function [path_value] = cal_path_value(pop, x)
  4. [n, ~] = size(pop);
  5. path_value = zeros(1, n);
  6. %循环计算每一条路径的长度
  7. for i = 1 : n
  8. single_pop = pop{i, 1};
  9. [~, m] = size(single_pop);
  10. %路径有m个栅格,需要计算m-1
  11. for j = 1 : m - 1
  12. % 点i所在列(从左到右编号1.2.3...)
  13. x_now = mod(single_pop(1, j), x) + 1;
  14. % 点i所在行(从上到下编号行1.2.3...)
  15. y_now = fix(single_pop(1, j) / x) + 1;
  16. % 点i+1所在列、行
  17. x_next = mod(single_pop(1, j + 1), x) + 1;
  18. y_next = fix(single_pop(1, j + 1) / x) + 1;
  19. %如果相邻两个栅格为上下或左右,路径长度加1,否则为对角线,长度加根号2
  20. if abs(x_now - x_next) + abs(y_now - y_next) == 1
  21. path_value(1, i) = path_value(1, i) + 1;
  22. else
  23. path_value(1, i) = path_value(1, i) + sqrt(2);
  24. end
  25. end
  26. end

4.计算路径平滑度函数cal_path_smooth.m

  1. %% 计算路径平滑度函数
  2. %jubobolv369
  3. function [path_smooth] = cal_path_smooth(pop, x)
  4. [n, ~] = size(pop);
  5. path_smooth = zeros(1, n);
  6. %循环计算每一条路径的平滑度
  7. for i = 1 : n
  8. single_pop = pop{i, 1};
  9. [~, m] = size(single_pop);
  10. %路径有m个栅格,需要计算m-1
  11. for j = 1 : m - 2
  12. % 点i所在列(从左到右编号1.2.3...)
  13. x_now = mod(single_pop(1, j), x) + 1;
  14. % 点i所在行(从上到下编号行1.2.3...)
  15. y_now = fix(single_pop(1, j) / x) + 1;
  16. % 点i+1所在列、行
  17. x_next1 = mod(single_pop(1, j + 1), x) + 1;
  18. y_next1 = fix(single_pop(1, j + 1) / x) + 1;
  19. % 点i+2所在列、行
  20. x_next2 = mod(single_pop(1, j + 2), x) + 1;
  21. y_next2 = fix(single_pop(1, j + 2) / x) + 1;
  22. %path_smooth(1, i) = path_smooth(1, i) + abs(atan(abs(x_now - x_next1)/abs(y_now - y_next1))-atan(abs(x_next2 - x_next1)/abs(y_next2 - y_next1)));
  23. %a2 = (x_now - x_next1)^2 + (y_now - y_next1)^2;
  24. %b2 = (x_next2 - x_next1)^2 + (y_next2 - y_next1)^2;
  25. c2 = (x_now - x_next2)^2 + (y_now - y_next2)^2;
  26. %angle = (a2 + c2 - b2) / (2 * sqrt(a2) * sqrt(c2));
  27. %若大于4小于等于8,说明此栅格与隔一个的栅格隔一行或一列且列或行相邻
  28. if c2 < 8 && c2 > 4
  29. path_smooth(1, i) = path_smooth(1, i) + 5;
  30. %若大于1小于等于4,说明此栅格与隔一个的栅格为对角,也可能或同行或同列垮了一格
  31. elseif c2 <= 4 && c2 > 1
  32. path_smooth(1, i) = path_smooth(1, i) + 30;
  33. %若等于1,说明此栅格与隔一个的栅格是上下或左右相邻,其路径不如直接从此格到邻格,显然冗余了。
  34. elseif c2 <= 1
  35. path_smooth(1, i) = path_smooth(1, i) + 5000;
  36. %否则不设置值,也即值为0,此时此栅格与隔一个的栅格是正方形对角的关系,最好。
  37. end
  38. end
  39. end

5.用轮盘堵法选择新的个体selection.m

  1. %% 用轮盘堵法选择新的个体
  2. % 输入变量:pop元胞种群,fitvalue:适应度值
  3. % 输出变量:newpop选择以后的元胞种群
  4. %jubobolv369
  5. function [new_pop] = selection(pop, fit_value)
  6. %构造轮盘
  7. [px, ~] = size(pop);
  8. total_fit = sum(fit_value);
  9. p_fit_value = fit_value / total_fit;
  10. p_fit_value = cumsum(p_fit_value); % B = cumsum(A) 从 A 中的第一个其大小不等于 1 的数组维度开始返回 A 的累积和。
  11. % 随机数从小到大排列
  12. ms = sort(rand(px, 1));
  13. fitin = 1;
  14. newin = 1;
  15. while newin <= px
  16. if(ms(newin)) < p_fit_value(fitin)
  17. new_pop{newin, 1} = pop{fitin, 1};
  18. newin = newin+1;
  19. else
  20. fitin = fitin+1;
  21. end
  22. end

6.交叉操作crossover.m

  1. %%交叉操作
  2. %输入变量:pop:父代种群,pc:交叉的概率
  3. %输出变量:newpop:交叉后的种群
  4. %jubobolv369
  5. function [new_pop] = crossover(pop, pc)
  6. [px,~] = size(pop);
  7. % 判断路径点数是奇数或偶数
  8. parity = mod(px, 2);
  9. new_pop = {};
  10. %两个两个交叉
  11. for i = 1:2:px-1
  12. singal_now_pop = pop{i, 1};
  13. singal_next_pop = pop{i+1, 1};
  14. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  15. %% A = [5 3 4 2]; %%
  16. %% B = [2 4 4 4 6 8]; %%
  17. %% [Lia,Locb] = ismember(A,B) %%
  18. %% Lia = 1x4 logical array %%A的每个元素若B中存在则该位为1 否则为零
  19. %% 0 0 1 1 %%
  20. %% Locb = 1×4 %%每个相同的元素在B中的索引
  21. %% 0 0 2 1 %%
  22. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  23. [lia, locb] = ismember(singal_now_pop, singal_next_pop);%[Lia,Locb] = ismember(A,B)确定 A 的哪些元素同时也在 B 中及其在 B 中的相应位置。
  24. [~, n] = find(lia == 1);%要查找特定的整数值,使用 == 运算符。返回找到的值在lia中的索引
  25. [~, m] = size(n);
  26. %如果随机数小于交叉概率且A中有三个以上路径节点与B中的相同
  27. if (rand < pc) && (m >= 3)
  28. % 生成一个2到m-1之间的随机数,也就是除去开头和结尾,在两条路径的相同节点中随机选取一个节点用于交叉
  29. r = round(rand(1,1)*(m-3)) +2;%Y = round(X) 将 X 的每个元素四舍五入为最近的整数
  30. crossover_index1 = n(1, r);%
  31. crossover_index2 = locb(crossover_index1);
  32. new_pop{i, 1} = [singal_now_pop(1:crossover_index1), singal_next_pop(crossover_index2+1:end)];
  33. new_pop{i+1, 1} = [singal_next_pop(1:crossover_index2), singal_now_pop(crossover_index1+1:end)];
  34. else %否则不交叉
  35. new_pop{i, 1} =singal_now_pop;
  36. new_pop{i+1, 1} = singal_next_pop;
  37. end
  38. %如果有奇数条路径,除最后一条外,其余已按照if的条件进行了是否交叉的处理,所以最后一条仍然不变。
  39. if parity == 1
  40. new_pop{px, 1} = pop{px, 1};
  41. end
  42. end

7.变异操作mutation.m

  1. %% 变异操作
  2. % 函数说明
  3. % 输入变量:pop:种群,pm:变异概率
  4. % 输出变量:newpop变异以后的种群
  5. %jubobolv369
  6. function [new_pop] = mutation(pop, pm, Grid, x)
  7. [px, ~] = size(pop);
  8. new_pop = {};
  9. %对每一行选择是否变异
  10. for i = 1:px
  11. % 初始化最大迭代次数
  12. max_iteration = 0;
  13. single_new_pop = pop{i, 1};
  14. [~, m] = size(single_new_pop);
  15. % single_new_pop_slice初始化
  16. single_new_pop_slice = [];
  17. if(rand < pm)
  18. while isempty(single_new_pop_slice)
  19. % 生成2到(m-1)的两个随机数,并排序
  20. mpoint = sort(round(rand(1,2)*(m-3)) + [2 2]);
  21. %切除掉包含两个随机数在内的之间的路径节点,将切除部分及前后两个节点取出
  22. single_new_pop_slice = [single_new_pop(mpoint(1, 1)-1) single_new_pop(mpoint(1, 2)+1)];
  23. %将取出的用于切除的部分路径重新联结成无间断路径(这一步可能变异 也可能不变异)
  24. single_new_pop_slice = generate_continuous_path(single_new_pop_slice, Grid, x);
  25. %max_iteration = max_iteration + 1;
  26. if max_iteration >= 100000
  27. break
  28. end
  29. end
  30. if max_iteration >= 100000
  31. new_pop{i, 1} = pop{i, 1};
  32. else
  33. %将变异后的路径保存
  34. new_pop{i, 1} = [single_new_pop(1, 1:mpoint(1, 1)-1), single_new_pop_slice(2:end-1), single_new_pop(1, mpoint(1, 2)+1:m)];
  35. end
  36. % single_new_pop_slice再次初始化
  37. single_new_pop_slice = [];
  38. else%不变异
  39. new_pop{i, 1} = pop{i, 1};
  40. end
  41. end

8.创建具有障碍物的栅格地图DrawMap.m

  1. %创建具有障碍物的栅格地图
  2. %矩阵中1代表黑色栅格
  3. %jubobolv369
  4. function Grid = DrawMap(Grid)
  5. b = Grid;
  6. b(end+1,end+1) = 0;
  7. colormap([1 1 1;0 0 0]); % 创建颜色
  8. pcolor(0.5:size(Grid,2) + 0.5, 0.5:size(Grid,1) + 0.5, b); % 赋予栅格颜色
  9. set(gca, 'XTick', 1:size(Grid,1), 'YTick', 1:size(Grid,2)); % 设置坐标
  10. axis image xy; % 沿每个坐标轴使用相同的数据单位,保持一致

如果急看,可至此处,压缩包包含代码和本人学习时候的草稿。喜欢请点赞哦。

 

链接: https://pan.baidu.com/s/19Z0huAtdR5x2WmBQdAbhHg

提取码: uzdu

文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览42577 人正在系统学习中