-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
573 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
|
||
addpath(genpath('robotcore')) | ||
clear; | ||
clc; | ||
|
||
%% 定义参考路径 | ||
% %参考路径1 | ||
path = [2.00 1.00; | ||
1.25 1.75; | ||
2.00 5.00; | ||
5.25 8.25; | ||
7.25 8.75; | ||
11.75 10.75; | ||
12.00 10.00]; | ||
% | ||
% % 参考路径2 | ||
% pathx = (0:pi/50:3*pi); | ||
% pathy = 10*exp(-0.5*pathx).*sin(0.5*pi*pathx); | ||
|
||
% 参考路径3 | ||
% pathx = 0:0.5:15; | ||
% pathy = sqrt(pathx) + sin(pathx); | ||
% path = [pathx', pathy']; | ||
|
||
%% 相关参数定义 | ||
H = 1; % 车辆轴距,单位:m | ||
goalRadius = 0.05; % 当车辆距离目标点小于此值时结束跟踪 | ||
sampleTime = 0.1; % 仿真时间,单位s | ||
vizRate = rateControl(10); % 控制频率 | ||
|
||
% 设置机器人初始状态 | ||
robotInitialLocation = path(1,:); % 初始位置 | ||
initialOrientation = 0; % 初始航向角 | ||
robotCurrentPose = [robotInitialLocation initialOrientation]'; % [x; y; theta]; | ||
v0 = 0; % 初始线速度 | ||
w = 0; % 初始角速度 | ||
|
||
robotGoal = path(end,:); % 确定目标点 | ||
vr = 2; % 目标线速度 | ||
distanceToGoal = norm(robotInitialLocation - robotGoal); % 计算当前位置与目标点的距离 | ||
v = v0; % 初始速度 | ||
yaw = initialOrientation; % 初始航向角 | ||
|
||
% 确定车辆框架尺寸以最接近代表车辆 | ||
frameSize = H/0.5; | ||
|
||
con = 0.4; % 视距常数 | ||
k = 0.4; % 倍率 | ||
% 轨迹预处理, 使得相邻轨迹点之间的距离不小于con | ||
x_tmp = []; | ||
y_tmp = []; | ||
for i=1:size(path,1)-1 | ||
add_points = floor(sqrt((path(i,1) - path(i+1,1)) ^ 2 + (path(i,2) - path(i+1,2)) ^ 2) / con) + 2; | ||
x_tmp = [x_tmp, linspace(path(i,1), path(i+1,1), add_points)]; | ||
y_tmp = [y_tmp, linspace(path(i,2), path(i+1,2), add_points)]; | ||
end | ||
path = [x_tmp, path(size(path,1),1); y_tmp, path(size(path,1),2)]'; | ||
|
||
while( distanceToGoal > goalRadius ) | ||
% 更新轨迹跟踪图 | ||
hold off | ||
|
||
% 绘制参考轨迹 | ||
plot(path(:,1), path(:,2),"k--d") | ||
hold all | ||
|
||
% 计算控制器的输出,将其输入到机器人中 | ||
[v, w] = pure_pursuit_control(robotCurrentPose, path, v, vr, k, con); % 机器人系下v与w | ||
|
||
% 使用控制输入得到机器人的速度 | ||
vel = derivative(robotCurrentPose, v, w, sampleTime); | ||
|
||
% 更新当前姿态 | ||
robotCurrentPose = robotCurrentPose + vel*sampleTime; | ||
|
||
% 重新计算与目标点的距离 | ||
distanceToGoal = norm(robotCurrentPose(1:2) - robotGoal(:)); | ||
|
||
% 绘制机器人的运行轨迹 | ||
% plotTrVec = [robotCurrentPose(1:2); 0]; | ||
% plotRot = axang2quat([0 0 1 robotCurrentPose(3)]); | ||
% plotTransforms(plotTrVec', plotRot, "MeshFilePath", "groundvehicle.stl", "Parent", gca, "View","2D", "FrameSize", frameSize); | ||
% light; | ||
|
||
scatter(robotCurrentPose(1), robotCurrentPose(2), 20, [0.5,0,0], 'filled'); | ||
plot([robotCurrentPose(1); robotCurrentPose(1) + 1 * cos(robotCurrentPose(3))], [robotCurrentPose(2); robotCurrentPose(2) + 1 * sin(robotCurrentPose(3))], 'color', [0.5,0,0]); | ||
|
||
% 设置图的横纵坐标 | ||
xlim([-5 15]); | ||
ylim([-5 15]); | ||
|
||
waitfor(vizRate); % 暂停代码执行,知道计时器vizRate出发,vizRate为采样频率 | ||
|
||
if distanceToGoal<0.1 % 到达目标后停止 | ||
break | ||
end | ||
end | ||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
function [v, w] = pure_pursuit_control(robotCurrentPose, path, v, vr, k, con) | ||
% 寻找离小车最近的点 | ||
now_index = 0; | ||
now_dist = 999999; | ||
for i=1:size(path,1) | ||
if sqrt((path(i,1) - robotCurrentPose(1)) ^ 2 + (path(i,2) - robotCurrentPose(2)) ^ 2) < now_dist | ||
now_dist = sqrt((path(i,1) - robotCurrentPose(1)) ^ 2 + (path(i,2) - robotCurrentPose(2)) ^ 2); | ||
now_index = i; | ||
end | ||
end | ||
% 选取目标点 | ||
tar_index = size(path,1); | ||
vis = v * k + con; % 预瞄距离 | ||
for i=now_index+1:size(path,1) | ||
if sqrt((path(i,1) - robotCurrentPose(1)) ^ 2 + (path(i,2) - robotCurrentPose(2)) ^ 2) > vis | ||
tar_index = i; | ||
break | ||
end | ||
end | ||
scatter(path(tar_index,1), path(tar_index,2), 20, 'b', 'filled'); % 绘制目标 | ||
% 计算相对位置 | ||
if tar_index ~= size(path,1) | ||
point_pose = atan2(path(tar_index+1,2) - path(tar_index,2), path(tar_index+1,1) - path(tar_index,1)); | ||
else | ||
point_pose = atan2(path(tar_index,2) - path(tar_index-1,2), path(tar_index,1) - path(tar_index-1,1)); | ||
end | ||
delPose = [path(tar_index, 1:2)'; point_pose] - robotCurrentPose; | ||
delPose = [ cos(robotCurrentPose(3)), sin(robotCurrentPose(3)), 0; | ||
-sin(robotCurrentPose(3)), cos(robotCurrentPose(3)), 0; | ||
0, 0, 1] * delPose; | ||
if delPose(3) > pi | ||
delPose(3) = delPose(3) - 2*pi; | ||
elseif delPose(3) < -pi | ||
delPose(3) = delPose(3) + 2*pi; | ||
end | ||
delPose | ||
v = v + 0.3*(vr - v); % 使用单P控制器实现线速度的控制 | ||
w = 2 * v * delPose(2) / (delPose(1)^2 + delPose(2)^2); | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
function [route,numExpanded,I,J] = AStarGrid (input_map, start_coords, dest_coords) | ||
% 在一个网格上运行 A* 算法 | ||
% Inputs : | ||
% input_map : 逻辑数组,其中自由空间单元格为 false 或 0 | ||
% 障碍物为 true 或 1 | ||
% start_coords and dest_coords : 起点和终点单元格的坐标 | ||
% 第一个元素是行,第二个是列 | ||
% Output : | ||
% route : 包含沿从起点到终点的最短路径的单元格的线性索引的数组 | ||
% 如果没有路径,则为空数组。这是一个一维向量。 | ||
% numExpanded: 记得同时返回你在搜索过程中扩展的总节点数 | ||
% 不要将目标节点计算为扩展节点 | ||
|
||
% 用一个map矩阵来表示每个点的状态 | ||
% 设置用于显示的颜色映射 | ||
% 1 - white - 空白单元格 | ||
% 2 - black - 障碍物 | ||
% 3 - red - 相当于CLOSED列表的作用 | ||
% 4 - blue - 相当于OPEN列表的作用 | ||
% 5 - green - 起点 | ||
% 6 - yellow - 目的地 | ||
|
||
cmap = [1 1 1; ... 白色,表示空闲的格子 | ||
0 0 0; ... 黑色,表示障碍物 | ||
1 0 0; ... 红色,表示已访问的格子 | ||
0 0 1; ... 蓝色,表示正在考虑的格子 | ||
0 1 0; ... 绿色,表示起点 | ||
1 1 0; ... 黄色,表示终点 | ||
0.5 0.5 0.5]; %灰色,表示路径上的格子 | ||
colormap(cmap); | ||
|
||
% 是否将每次迭代地图进行可视化展示 | ||
drawMapEveryTime = true; | ||
[nrows, ncols] = size(input_map); | ||
|
||
% map - 一个二维数组,用于跟踪每个格子的状态 | ||
map = zeros(nrows,ncols); | ||
|
||
map(~input_map) = 1; % 标记空闲格子 | ||
map(input_map) = 2; % 标记障碍物格子 | ||
|
||
% 产生起点和终点的线性索引 | ||
start_node = sub2ind(size(map), start_coords(1), start_coords(2)); | ||
dest_node = sub2ind(size(map), dest_coords(1), dest_coords(2)); | ||
map(start_node) = 5; % 标记起点 | ||
map(dest_node) = 6; % 标记终点 | ||
|
||
parent = zeros(nrows,ncols); % 用来记录每个节点的父节点 | ||
[X, Y] = meshgrid (1:ncols, 1:nrows); % 函数可以将输入的向量扩展为二维网格 | ||
|
||
xd = dest_coords(1); % 目标节点的 x 坐标 | ||
yd = dest_coords(2); % 目标节点的 y 坐标 | ||
|
||
% 用曼哈顿距离作为启发式函数 | ||
% H = abs(X - xd) + abs(Y - yd); | ||
% 用欧氏距离距离作为启发式函数 | ||
H = sqrt((X - xd).*(X-xd) + (Y - yd).*(Y-yd)); | ||
H = H'; | ||
|
||
% 初始化成本评价函数,将代价设置为正无穷表示还没探索过这些节点 | ||
f = Inf(nrows, ncols); | ||
g = Inf(nrows, ncols); | ||
|
||
g(start_node) = 0; | ||
f(start_node) = H(start_node); | ||
|
||
% 记录已经被探索的节点数 | ||
numExpanded = 0; | ||
|
||
% Main Loop | ||
while true | ||
if (drawMapEveryTime) | ||
map1=imrotate(map,90); | ||
image(0.5, 0.5, map1); | ||
axis image; % 设置坐标轴的宽高比为1,使地图绘制时不发生形变 | ||
drawnow; % 立即更新图形窗口 | ||
end | ||
|
||
% 寻找f最小的点,并返回最小值min_f和对应的索引current | ||
[min_f, current] = min(f(:) + abs(map(:) - 4) * 10000); % 只会访问open(map=4)的点 | ||
|
||
% 判断条件是否满足其中之一,说明已找最短路径或无法到达终点 | ||
% 跳出循环,结束路径搜索 | ||
if ((current == dest_node) || isinf(min_f)) | ||
break; | ||
end | ||
|
||
% 更新地图 | ||
map(current) = 3; % 将当前节点标记为已访问状态 | ||
numExpanded = numExpanded + 1; | ||
|
||
% 计算当前节点的行列坐标 | ||
[i, j] = ind2sub(size(f), current); | ||
|
||
% ********************************************************************* | ||
% 两行星号*之间编写代码,实现以下功能: | ||
% 访问当前节点的每个相邻节点 | ||
% 根据访问结果更新地图、f和g和父节点表 | ||
% 访问节点 | ||
if i > 1 | ||
if map(i-1, j) == 1 || map(i-1, j) == 6 | ||
map(i-1, j) = 4; | ||
parent(i-1, j) = sub2ind(size(map), i, j); | ||
g(i-1, j) = g(i, j) + 0.1; | ||
end | ||
end | ||
if j > 1 | ||
if map(i, j-1) == 1 || map(i, j-1) == 6 | ||
map(i, j-1) = 4; | ||
parent(i, j-1) = sub2ind(size(map), i, j); | ||
g(i, j-1) = g(i, j) + 0.1; | ||
end | ||
end | ||
if i < nrows | ||
if map(i+1, j) == 1 || map(i+1, j) == 6 | ||
map(i+1, j) = 4; | ||
parent(i+1, j) = sub2ind(size(map), i, j); | ||
g(i+1, j) = g(i, j) + 0.1; | ||
end | ||
end | ||
if j < ncols | ||
if map(i, j+1) == 1 || map(i, j+1) == 6 | ||
map(i, j+1) = 4; | ||
parent(i, j+1) = sub2ind(size(map), i, j); | ||
g(i, j+1) = g(i, j) + 0.1; | ||
end | ||
end | ||
f = g + H; | ||
%********************************************************************* | ||
end | ||
|
||
%% 构建从起点到终点的路径,并进行可视化 | ||
|
||
if (isinf(f(dest_node))) % 判断是否存在路径 | ||
route = []; | ||
else | ||
% ********************************************************************* | ||
% 两行星号*之间编写代码,实现以下功能: | ||
% 构建从终点到起点回溯路径 | ||
route = []; | ||
I = []; | ||
J = []; | ||
now = dest_node; | ||
while now ~= 0 % 循环在起点停止 | ||
route = [route now]; | ||
I = [I X(now)]; | ||
J = [J Y(now)]; | ||
now = parent(now); | ||
end | ||
numExpanded = numExpanded - 1; % 长度去除终点 | ||
I = I - 0.5; | ||
J = J - 0.5; | ||
|
||
% 重绘起点与终点 | ||
map(start_node) = 5; | ||
map(dest_node) = 6; | ||
|
||
% ********************************************************************* | ||
|
||
% 用于可视化地图和路径的代码片段 | ||
for k = 2:length(route) - 1 | ||
map(route(k)) = 7; | ||
pause(0.04); | ||
map1 = imrotate(map,90); | ||
image(0.5, 0.5, map1); | ||
grid on; | ||
axis image; | ||
end | ||
|
||
end | ||
end |
Oops, something went wrong.