Índice
2 Algoritmo de pesquisa RRT baseado em Matlab
3 Desenho de empilhamento personalizado baseado em Matlab
4 Evitação de obstáculos no caminho de empilhamento personalizado com base no algoritmo RRT
fundo
Durante o processo de planejamento do caminho do braço do robô de paletização , é necessário fornecer o caminho ideal sem colisões para a próxima caixa com base no status de paletização das caixas existentes. O algoritmo de árvore aleatória de busca rápida RRT é um algoritmo de planejamento global de crescimento incremental baseado em amostragem aleatória e também é o método mais comumente usado no movimento de planejamento de braço de robô.
1 algoritmo de pesquisa RRT
O ponto inicial e o ponto final do caminho do robô são conhecidos no ambiente espacial . O algoritmo RRT usa o ponto inicial como nó raiz, gera pontos aleatórios no espaço do robô , atravessa a árvore aleatória para encontrar o nó folha mais próximo e expande passo paranódo , pegue o novo nó e execute a detecção de colisão nele ; se a detecção for aprovada, ele será incluído na árvore aleatória, caso contrário o crescimento será abandonado. Repita as etapas acima até que o ponto alvo seja encontrado , o que significa que a busca do caminho foi concluída. O princípio do algoritmo RRT tradicional é mostrado na figura abaixo.
Comparado com outros algoritmos, o algoritmo RRT é mais adequado para planejamento espacial de alta dimensão , mas também apresenta algumas falhas. Como os pontos aleatórios não têm direcionalidade, a velocidade de convergência é lenta ; ao encontrar muitos obstáculos, o algoritmo RRT tradicional é fácil de entrar em áreas locais.Para o problema do valor mínimo, tendo em conta as deficiências do algoritmo RRT tradicional, atualmente um algoritmo comum melhorado tem uma estratégia de viés alvo para acelerar a convergência.
A essência do RRT é baseada no método de amostragem espacial, embora não seja ideal, mas é probabilisticamente completo . O núcleo deste tipo de algoritmo está na amostragem aleatória, começando no nó pai, gerando aleatoriamente nós filhos no mapa, conectando os nós pai e filho e realizando a detecção de colisão. Se não houver colisão, o nó filho é expandido.
2 Algoritmo de pesquisa RRT baseado em Matlab
%% 确定障碍物空间(以长方体为例,在z方向上有共50的膨胀大小)
origin = [100,0,50];
rectsize=[200,30,150];
%下面开始绘制障碍物,[长 宽 高]=[200 30 100]的矩形
figure(1);
plotcube([200 30 100],[0 -15 -25],1,[1 0 0]); % ([长 宽 高],[立方体初始顶点位置],1,[颜色])
axis equal
%% 参数
source=[100 100 10]; % 初始点
goal=[100 -100 10]; % 目标点
stepsize = 5;
threshold = 5;
maxFailedAttempts = 10000; % 最大搜索次数
display = true;
searchsize = [200 400 200]; %探索空间六面体
%% 绘制起点和终点
hold on;
scatter3(source(1),source(2),source(3),"filled","g");
scatter3(goal(1),goal(2),goal(3),"filled","b");
tic; % tic-toc: Functions for Elapsed Time
RRTree = double([source -1]);
failedAttempts = 0;
pathFound = false;
%% 循环(开始RRT搜索)
while failedAttempts <= maxFailedAttempts % loop to grow RRTs
%% chooses a random configuration
if rand < 0.5
sample = (rand(1,3)-[0 0.75 0.2]); % random sample
sample = sample .* searchsize;
else
sample = goal; % sample taken as goal to bias tree generation to goal
end
%% selects the node in the RRT tree that is closest to qrand
[A, I] = min( distanceCost(RRTree(:,1:3),sample) ,[],1); % find the minimum value of each column
closestNode = RRTree(I(1),1:3);
%% moving from qnearest an incremental distance in the direction of qrand
movingVec = [sample(1)-closestNode(1),sample(2)-closestNode(2),sample(3)-closestNode(3)];
movingVec = movingVec/sqrt(sum(movingVec.^2)); %单位化
if rand < 0.5
newPoint=closestNode + stepsize * movingVec;
else
newPoint=goal;
end
% checkPath3判断路径与障碍物是否发生碰撞的函数
if ~checkPath3(closestNode, newPoint, origin,rectsize) % if extension of closest node in tree to the new point is feasible
failedAttempts = failedAttempts + 1;
continue;
end
if distanceCost(newPoint,goal) < threshold, pathFound = true; break; end % goal reached
[A, I2] = min( distanceCost(RRTree(:,1:3),newPoint) ,[],1); % check if new node is not already pre-existing in the tree
if distanceCost(newPoint,RRTree(I2(1),1:3)) < threshold, failedAttempts = failedAttempts + 1; continue; end
RRTree = [RRTree; newPoint I(1)]; % add node
failedAttempts = 0;
if display, plot3([closestNode(1);newPoint(1)],[closestNode(2);newPoint(2)],[closestNode(3);newPoint(3)],'LineWidth',1); end
pause(0.05);
end
if display && pathFound, plot3([closestNode(1);goal(1)],[closestNode(2);goal(2)],[closestNode(3);goal(3)]); end
% if display, disp('click/press any key'); waitforbuttonpress; end
if ~pathFound, error('no path found. maximum attempts reached'); end
%% retrieve path from parent information
path = goal;
prev = I(1);
while prev > 0
path = [RRTree(prev,1:3); path];
prev = RRTree(prev,4);
end
pathLength = 0;
for i=1:length(path(:,1))-1, pathLength = pathLength + distanceCost(path(i,1:3),path(i+1,1:3)); end % calculate path length
fprintf('processing time=%d \nPath Length=%d \n\n', toc, pathLength);
figure(2)
plotcube([200 30 100],[0 -15 -25],1,[1 0 0]);
axis equal
hold on;
scatter3(source(1),source(2),source(3),"filled","g");
scatter3(goal(1),goal(2),goal(3),"filled","b");
plot3(path(:,1),path(:,2),path(:,3),'LineWidth',2,'color','y');
①A função de detecção de colisão checkPath3.m é:
%% checkPath3.m
function feasible=checkPath3(n,newPos,origin, size)
feasible=true;
size=size/2;
% disp(size);
movingVec = [newPos(1)-n(1),newPos(2)-n(2),newPos(3)-n(3)];
movingVec = movingVec/sqrt(sum(movingVec.^2)); %单位化
% 判断是否与障碍物立方体(以立方体中心为基准的空间边界计算)相交
if (n(1) < (origin(1)+size(1)) && n(1) > (origin(1)-size(1))) && (n(2) < (origin(2)+size(2)) && n(2) > (origin(2)-size(2))) && (n(3) < (origin(3)+size(3)) && n(3) > (origin(3)-size(3)))
feasible=false;
return;
elseif (newPos(1) < (origin(1)+size(1)) && newPos(1) > (origin(1)-size(1))) && (newPos(2) < (origin(2)+size(2)) && newPos(2) > (origin(2)-size(2))) && (newPos(3) < (origin(3)+size(3)) && newPos(3) > (origin(3)-size(3)))
feasible=false;
return;
else
t=(origin(1)+size(1)-n(1))/movingVec(1);
y=n(2)+movingVec(2)*t;
z=n(3)+movingVec(3)*t;
if (y < (origin(2)+size(2)) && y > (origin(2)-size(2))) && (z < (origin(3)+size(3)) && z > (origin(3)-size(3)))
feasible=false;
return;
end
t=(origin(1)-size(1)-n(1))/movingVec(1);
y=n(2)+movingVec(2)*t;
z=n(3)+movingVec(3)*t;
if (y < (origin(2)+size(2)) && y > (origin(2)-size(2))) && (z < (origin(3)+size(3)) && z > (origin(3)-size(3)))
feasible=false;
return;
end
t=(origin(2)+size(2)-n(2))/movingVec(2);
x=n(1)+movingVec(1)*t;
z=n(3)+movingVec(3)*t;
if (x < (origin(1)+size(1)) && x > (origin(1)-size(1))) && (z < (origin(3)+size(3)) && z > (origin(3)-size(3)))
feasible=false;
return;
end
t=(origin(2)-size(2)-n(2))/movingVec(2);
x=n(1)+movingVec(1)*t;
z=n(3)+movingVec(3)*t;
if (x < (origin(1)+size(1)) && x > (origin(1)-size(1))) && (z < (origin(3)+size(3)) && z > (origin(3)-size(3)))
feasible=false;
return;
end
t=(origin(3)+size(3)-n(3))/movingVec(3);
x=n(1)+movingVec(1)*t;
y=n(2)+movingVec(2)*t;
if (x < (origin(1)+size(1)) && x > (origin(1)-size(1))) && (y < (origin(2)+size(2)) && y > (origin(2)-size(2)))
feasible=false;
return;
end
t=(origin(3)-size(3)-n(3))/movingVec(3);
x=n(1)+movingVec(1)*t;
y=n(2)+movingVec(2)*t;
if (x < (origin(1)+size(1)) && x > (origin(1)-size(1))) && (y < (origin(2)+size(2)) && y > (origin(2)-size(2)))
feasible=false;
return;
end
end
end
②A função de cálculo de distância distanceCost.m entre dois pontos:
function h=distanceCost(a,b) %% distanceCost.m
h = sqrt(sum((a-b).^2, 2));
end
Os resultados da operação são:
Pode-se ver que o lado esquerdo mostra o processo de busca de amostragem no espaço.Quando a linha que conecta o ponto de amostragem e o ponto final não colide cruzadamente com o espaço de colisão [expanded rectsize=[200,30,150]], a reta linha atinge o ponto final. Esportes é o resultado de pesquisa mais rápido.
3 Desenho de empilhamento personalizado baseado em Matlab
Aqui, as pilhas são definidas no formato de um cubóide e o desenho é concluído com a ajuda da função plotcube. [ plotcube ] precisa preparar a posição do vértice, comprimento, largura, altura e configurações de cor do cubóide ao usá-lo, para que as configurações dos parâmetros do cubóide sejam inicializadas lendo os dados da tabela [ readmatrix ("XXX.xls")].
Por exemplo , os dados da tabela de paralelepípedos retangulares empilhados são os seguintes:
Nota : Matlab lê apenas os dados numéricos da imagem acima , ou seja, a partir da segunda linha (a primeira linha é uma descrição de string como BoxSize_L, que não é lida durante o processamento de dados)
Os parâmetros na primeira linha representam:
BoxSize_L, BoxSize_W, BoxSize_H: comprimento, largura e altura das caixas empilhadas
Position_X,Position_Y,Position_Z: As coordenadas da posição do vértice da caixa
ColorMode: o número da configuração de cor
Consulte as configurações de valor RGB na documentação oficial do Matlab . O código de configuração de cores é o seguinte:
ColorMode = [[0.4940 0.1840 0.5560];
[0.4660 0.6740 0.1880];
[0.3010 0.7450 0.9330];
[0.6350 0.0780 0.1840]];
StackNum: A mesma pilha de caixas tem o mesmo número (as 4 pilhas de caixas definidas aqui)
O código para desenhar dados do tipo pilha com base na tabela acima é o seguinte:
Boxes = readmatrix('PalletBoxData_CSDN.xls','Range','C2:J18'); %'C2:J18'对应的是上述图片中的数值数据(第一行是BoxSize_L等字符串描述,数据处理的时候不读入)
ColorMode = [[0.4940 0.1840 0.5560]; % 指定绘图颜色
[0.4660 0.6740 0.1880];
[0.3010 0.7450 0.9330];
[0.6350 0.0780 0.1840]];
figure(1);
plot_Obstacle(Boxes,ColorMode) % 绘制堆垛现状(障碍物)
function plot_Obstacle(Boxes,ColorMode)
% 绘制码垛
% figure(1);
hold on;
for i=1:length(Boxes(:,1))
plotcube([Boxes(i,1) Boxes(i,2) Boxes(i,3)],[Boxes(i,4) Boxes(i,5) Boxes(i,6)],1,ColorMode(Boxes(i,7),:));
hold on
end
axis equal
end
O gráfico resultante é o seguinte:
4 Evitação de obstáculos no caminho de empilhamento personalizado com base no algoritmo RRT
Para combinar o conteúdo dos Capítulos 2 e 3, primeiro leia os dados da tabela de formato de pilha personalizada e use esse formato de pilha como um obstáculo espacial para planejar o caminho RRT para evitar obstáculos. [Significado físico: Durante o processo de paletização do braço robótico, as caixas transportadas não podem colidir com o tipo de paletização existente. 】
O código geral é o seguinte:
clear all
clc
%% 读取码垛箱子的位置(上图中的表格数据)
Boxes = readmatrix('PalletBoxData_CSDN.xls','Range','C2:J18');
ColorMode = [[0.4940 0.1840 0.5560]; % 指定绘图颜色,参考https://ww2.mathworks.cn/help/matlab/creating_plots/specify-plot-colors.html
[0.4660 0.6740 0.1880];
[0.3010 0.7450 0.9330];
[0.6350 0.0780 0.1840]];
figure(1);
plot_Obstacle(Boxes,ColorMode) % 绘制堆垛现状(障碍物)
%% 初始化参数
% 障碍物空间
StackNum = Boxes(:,8); % 获取码垛编号
StackHeight = []; % 每一堆垛箱子的总高度
h_dialate = 0; % 障碍物在高度上膨胀一定距离
[origin,rectsize] = calc_obstacleSpace(Boxes,StackNum,h_dialate,StackHeight); % 计算障碍物空间
searchsize = [300,200,600]; %探索空间六面体
source=[315 -200 0]; % 初始点
goal=[0 200 88]; % 目标点
stepsize = 20;
threshold = 5;
maxFailedAttempts = 10000; % 最大搜索次数
display = true;
searchsize = [200 400 200]; %探索空间六面体
%% 绘制起点和终点
hold on;
scatter3(source(1),source(2),source(3),"filled","g");
scatter3(goal(1),goal(2),goal(3),"filled","b");
tic; % tic-toc: Functions for Elapsed Time
RRTree = double([source -1]);
failedAttempts = 0;
pathFound = false;
%% 循环(开始RRT搜索)
while failedAttempts <= maxFailedAttempts % loop to grow RRTs
%% chooses a random configuration
if rand < 0.5
sample = (rand(1,3)-[0 0.75 0.2]); % random sample
sample = sample .* searchsize;
else
sample = goal; % sample taken as goal to bias tree generation to goal
end
%% selects the node in the RRT tree that is closest to qrand
[A, I] = min( distanceCost(RRTree(:,1:3),sample) ,[],1); % find the minimum value of each column
closestNode = RRTree(I(1),1:3);
%% moving from qnearest an incremental distance in the direction of qrand
movingVec = [sample(1)-closestNode(1),sample(2)-closestNode(2),sample(3)-closestNode(3)];
movingVec = movingVec/sqrt(sum(movingVec.^2)); %单位化
if rand < 0.5
newPoint=closestNode + stepsize * movingVec;
else
newPoint=goal;
end
if ~checkPath3(closestNode, newPoint, origin,rectsize) % if extension of closest node in tree to the new point is feasible
failedAttempts = failedAttempts + 1;
continue;
end
t = [];
for i = 1:4
t(i) = ~checkPath3(closestNode, newPoint, origin(i,:),rectsize(i,:));
end
% 用 if判断及 或语句,保证不碰撞到每一个堆垛
if t(1)||t(2)||t(3)||t(4)% if extension of closest node in tree to the new point is feasible
failedAttempts = failedAttempts + 1;
continue; % continue一旦被执行(if成立),就会终止当前循环,进行下一次循环。
end
if distanceCost(newPoint,goal) < threshold, pathFound = true; break; end % goal reached
[A, I2] = min( distanceCost(RRTree(:,1:3),newPoint) ,[],1); % check if new node is not already pre-existing in the tree
if distanceCost(newPoint,RRTree(I2(1),1:3)) < threshold, failedAttempts = failedAttempts + 1; continue; end
RRTree = [RRTree; newPoint I(1)]; % add node
failedAttempts = 0;
if display, plot3([closestNode(1);newPoint(1)],[closestNode(2);newPoint(2)],[closestNode(3);newPoint(3)],'LineWidth',1); end
pause(0.05);
end
if display && pathFound, plot3([closestNode(1);goal(1)],[closestNode(2);goal(2)],[closestNode(3);goal(3)]); end
% if display, disp('click/press any key'); waitforbuttonpress; end
if ~pathFound, error('no path found. maximum attempts reached'); end
%% 最终轨迹展示
path = goal;
prev = I(1);
while prev > 0
path = [RRTree(prev,1:3); path];
prev = RRTree(prev,4);
end
pathLength = 0;
for i=1:length(path(:,1))-1, pathLength = pathLength + distanceCost(path(i,1:3),path(i+1,1:3)); end % calculate path length
fprintf('processing time=%d \nPath Length=%d \n\n', toc, pathLength);
figure(2)
plot_Obstacle(Boxes,ColorMode) % 绘制堆垛现状(障碍物)
axis equal
hold on;
scatter3(source(1),source(2),source(3),"filled","g");
scatter3(goal(1),goal(2),goal(3),"filled","b");
plot3(path(:,1),path(:,2),path(:,3),'LineWidth',2,'color','y');
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%自定义函数%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 绘制障碍物(以长方体为例,主要是方便计算)
function plot_Obstacle(Boxes,ColorMode)
% 绘制码垛
% figure(1);
hold on;
for i=1:length(Boxes(:,1))
plotcube([Boxes(i,1) Boxes(i,2) Boxes(i,3)],[Boxes(i,4) Boxes(i,5) Boxes(i,6)],1,ColorMode(Boxes(i,7),:));
hold on
end
axis equal
end
% 计算障碍物空间
% StackNum:堆垛的个数; h_dialate:堆垛障碍物的膨胀高度
% origin:膨胀后的障碍物空间的中心点; rectsize:膨胀后的障碍物空间
function [origin,rectsize] = calc_obstacleSpace(Boxes,StackNum,h_dialate,StackHeight)
StackCount = hist(StackNum,unique(StackNum)); %获取每一堆有几个箱子
origin = []; % 膨胀后的障碍物空间的中心点
rectsize=[]; % 膨胀后的障碍物空间
for i=1:4 %%%%%%%%%%%%%%%%此时一共有4堆箱子
h = Boxes(find(StackNum==i),3); %分别求每一堆的箱子的高度(默认都是同一种箱子,高度相同)
h_i = StackCount(i)*h(1); %求每一堆的箱子总高度(目前累到的高度)
StackHeight = [StackHeight,h_i]; %箱子总高度列到一个列表中
x = Boxes(find(StackNum==i),4) + Boxes(find(StackNum==i),1)/2;
y = Boxes(find(StackNum==i),5) + Boxes(find(StackNum==i),2)/2;
%分别求每一堆的箱子的中心点位置x,y,z坐标(默认都是同一种箱子,高度相同)
x_center = x(1);
y_center = y(1);
z_center = h_i/2;
obstacle_center = [x_center,y_center,z_center];
%分别求每一堆的箱子的长、宽
l = Boxes(find(StackNum==i),1);
w = Boxes(find(StackNum==i),2);
l_i = l(1);
w_i = w(1);
obstacle_volumn = [l_i,w_i,h_i+h_dialate];
origin = cat(1,origin,obstacle_center); % 膨胀后的障碍物空间的中心点
rectsize = cat(1,rectsize,obstacle_volumn);
end
end
O resultado da operação é:
Muitas experiências descobriram que se o tamanho do passo (parâmetro stepsize) for grande, a pesquisa falhará devido a obstáculos grandes e complexos; se o tamanho do passo for pequeno, a pesquisa estará sempre em branco e não poderá convergir (a próxima posição em branco para o palete continuará a se expandir) espaço de pesquisa, não tem efeito).