728x90
728x90
clear; close all; clc;
rosshutdown;
rosinit('http://localhost:11311')
tftree = rostf;
pause(3);
% Parameter//============================================================
roi = [0, 20, -10, 10, -2, 4];
% init//==================================================================
params = lidarParameters('OS1Gen1-64',512);
velSub = rossubscriber('/odom_skid', "DataFormat", "struct");
gpsSub = rossubscriber('/odometry/gps', "DataFormat", "struct");
imuSub = rossubscriber('/imu/data', "DataFormat", "struct");
lidarSub = rossubscriber('/lidar/points', "DataFormat", "struct");
[pubClusters, markerArrayMsg] = rospublisher('/clusters_marker', 'visualization_msgs/MarkerArray',DataFormat='struct');
pubPath = rospublisher('/path_marker', 'visualization_msgs/Marker','DataFormat','struct');
detectParkingSpace = true;
pp=controllerPurePursuit;
pp.LookaheadDistance=4; % m
pp.DesiredLinearVelocity=1.3; % m/s
pp.MaxAngularVelocity = 1.5; % rad/s
x = 0:0.5:80;
y = zeros(size(x));
z = [x;y]';
pp.Waypoints = z;
while detectParkingSpace
lidarData = receive(lidarSub);
roiPtCloud = preprocess_lidar_data(lidarData, params, roi);
roiPtCloud = pcdenoise(roiPtCloud,PreserveStructure=true,NumNeighbors=30);
% 포인트클라우드 N 이상일때만 물체로 판단
[labels, numClusters] = pcsegdist(roiPtCloud,0.3,"NumClusterPoints",15);
vehiclePose = getPose(gpsSub, imuSub);
if numClusters > 1
pp.DesiredLinearVelocity=0.5; % m/s
end
if numClusters>5
%figure
%hold on;
con_info = zeros(numClusters,2);
pp.DesiredLinearVelocity=0.3;
for i = 1:numClusters
idx = find(labels == i);
cuboidModel = pcfitcuboid(roiPtCloud, idx);
points = getCornerPoints(cuboidModel);
% plot(points(1,1),points(1,2),'r.','MarkerSize',20);
% plot(points(2,1),points(2,2),'r.','MarkerSize',20);
% plot(points(3,1),points(3,2),'r.','MarkerSize',20);
% plot(points(4,1),points(4,2),'r.','MarkerSize',20);
con_info(i,:) = sum(points(1:4,1:2))/4;
end
score = 0;
for i = 1:numClusters
%plot(con_info(i,1),con_info(i,2),'b.','MarkerSize',20);
end
% -2 ~ -3 범위의 y 좌표를 가지는 장애물 필터링
filteredObstacles = con_info(con_info(:,2) >= -3 & con_info(:,2) <= 0, :);
% x 좌표에 따라 정렬
sortedObstacles = sortrows(filteredObstacles, 1);
% 장애물 간의 거리 계산
distances = sqrt(diff(sortedObstacles(:,1)).^2 + diff(sortedObstacles(:,2)).^2);
for i = 1 : size(distances,1)
if distances(i)>4
parkingSpot = sortedObstacles(i,:) + sortedObstacles(i+1,:);
parkingSpot = parkingSpot/2;
parkingSpot(2) = parkingSpot(2)-1.5;
%plot(parkingSpot(1),parkingSpot(2),'g.','MarkerSize',20);
detectParkingSpace = false;
break;
end
end
end
[v, w] = pp(vehiclePose); % Pass the current vehicle pose to the path planner
[pub, msg] = publish_twist_command(v, w, '/cmd_vel');
send(pub, msg);
end
[pub, msg] = publish_twist_command(0, 0, '/cmd_vel');
send(pub, msg);
%주차 알고리즘 시작
% figure;
lidarData = receive(lidarSub);
roiPtCloud = preprocess_lidar_data(lidarData, params, roi);
% 이진 맵 생성을 위한 그리드 초기화
xRange = -3:0.1:20;
yRange = -7:0.1:7;
binaryMap = zeros(length(yRange), length(xRange));
% 포인트 클라우드 데이터를 이진 맵으로 변환
for i = 1:size(roiPtCloud.Location, 1)
x = roiPtCloud.Location(i, 1);
y = -roiPtCloud.Location(i, 2);
z = roiPtCloud.Location(i,3);
% 좌표가 그리드 셀에 해당하는지 확인
xIdx = find(xRange <= x, 1, 'last');
yIdx = find(yRange <= y, 1, 'last');
% 이진 맵에 포인트 표시
if ~isempty(xIdx) && ~isempty(yIdx) && z > -0.4
binaryMap(yIdx, xIdx) = 1;
end
end
cellSize = 0.1; % 10cm
costmap = vehicleCostmap(binaryMap, 'CellSize', cellSize);
% 차량 치수 설정
vehicleDims = vehicleDimensions(2.4, 2.2, 1); % 길이, 너비, 휠베이스
vehicleDims.FrontOverhang = 0.3; % 앞 오버행
vehicleDims.RearOverhang = 0.5; % 뒤 오버행
% 충돌 검사기 설정
costmap.CollisionChecker.VehicleDimensions = vehicleDims;
ccConfig = costmap.CollisionChecker;
ccConfig.NumCircles = 2;
costmap.CollisionChecker = ccConfig;
%costmap.CollisionChecker = vehicleCollChecker('InflationRadius', 0.3);
costmap.CollisionChecker.InflationRadius = 0.8;
%currentPose = [0 0 0]; % [x, y, theta]
currentPose = [2 7 0]; %라이다 위치기준에서 후륜축 위치 기준으로
parkMotionPlanner = pathPlannerRRT(costmap, MinIterations=1000);
% Define desired pose for the parking spot, returned by the V2X system.
parkingSpot(1:2) = parkingSpot(1:2)+ currentPose(1:2);
parkPose = [parkingSpot 10];
preParkPose = currentPose;
% Change the connection method to allow for reverse motions.
parkMotionPlanner.ConnectionMethod = "Reeds-Shepp";
parkMotionPlanner.MinTurningRadius = 5; % meters
parkMotionPlanner.ConnectionDistance = 7; % meters
replan = true;
while replan
tic
refPath = plan(parkMotionPlanner, preParkPose, parkPose);
toc
% The path corresponding to the parking maneuver is small and requires
% precise maneuvering. Instead of interpolating only at transition poses,
% interpolate more finely along the length of the path.
if refPath.Length == 0
continue
end
numSamples = refPath.Length*2;
stepSize = refPath.Length / numSamples;
lengths = 0 : stepSize : refPath.Length;
[transitionPoses, directions] = interpolate(refPath, lengths);
% if (refPath.Length > 0)
% k = k;
% end
%plotParkingManeuver(costmap, refPath, preParkPose, parkPose)
% Replan if the path contains more than one direction switching poses
% or if the path is too long.
sum(abs(diff(directions(1:end-1))))
refPath.Length
replan = sum(abs(diff(directions(1:end-1))))>7 || refPath.Length > 50|| refPath.Length == 0;
end
%plotParkingManeuver(costmap, refPath, preParkPose, parkPose)
% Smooth the path.
approxSeparation = 0.3; % meters
numSmoothPoses = round(refPath.Length / approxSeparation);
minSeparation = 0.1;
[refPoses, directions, cumLengths, curvatures] = smoothPathSpline(transitionPoses, directions, numSmoothPoses, minSeparation);
% Generate velocity profile.
velMsg = receive(velSub);
currentVel = sqrt(velMsg.Twist.Twist.Linear.X.^2 + velMsg.Twist.Twist.Linear.Y.^2);
refVelocities = helperGenerateVelocityProfile(directions, cumLengths, curvatures, currentVel, 0, 0.3);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 주차 경로 월드 좌표로 변환
refPoses = refPoses- currentPose ;
%refPoses(1) = refPoses(1)- 0.3;
vehiclePose = getPose(gpsSub, imuSub);
vehiclePose(1) = vehiclePose(1)-0.5 ;
refPoses(:,1:2) = transformWaypointsToOdom(refPoses(:,1:2), vehiclePose);
markerIdPath = 0;
parkPose = parkPose-currentPose;
parkPose(1:2) = transformWaypointsToOdom(parkPose(1:2), vehiclePose);
%%%%%%%%%%%%%%%%% 경로 추종
%sampleTime = 2;
pathAnalyzer = HelperPathAnalyzer(Wheelbase=vehicleDims.Wheelbase);
pathAnalyzer.RefPoses = refPoses;
pathAnalyzer.Directions = directions;
pathAnalyzer.VelocityProfile = refVelocities;
pathAnalyzer.Curvatures = curvatures;
figure
hold on
plot(refPoses(:,1),refPoses(:,2));
isGoalReached = false;
v = 0;
currentDir = 1;
while ~isGoalReached
% Get current driving direction.
tic
currentPose = getPose(gpsSub, imuSub)';
currentPose(1) = currentPose(1) - 0.5*cos(currentPose(3));
currentPose(2) = currentPose(2) - 0.5*sin(currentPose(3));
theta = currentPose(3);
currentPose(3)= rad2deg(currentPose(3));
% Find the reference pose on the path and the corresponding velocity.
[refPose, refVel, direction] = pathAnalyzer(currentPose, currentVel);
plot(refPose(1),refPose(2),'r.','MarkerSize',20);
plot(currentPose(1),currentPose(2),'b.','MarkerSize',20);
% If the vehicle changes driving direction, reset vehicle velocity in
% the simulator and reset longitudinal controller.
v = refVel;
if currentDir ~= direction
%currentVel = 0;
if direction == -1
v = -0.1;
else
v = 0.1;
end
while currentVel > 0.03 || currentVel <-0.03
[pub, msg] = publish_twist_command(0, 0, '/cmd_vel');
send(pub, msg);
velMsg = receive(velSub);
currentVel = sqrt(velMsg.Twist.Twist.Linear.X.^2 + velMsg.Twist.Twist.Linear.Y.^2);
end
while abs(currentVel) +abs( v) <0.14
[pub, msg] = publish_twist_command(v, v*2, '/cmd_vel');
send(pub, msg);
velMsg = receive(velSub);
currentVel = sqrt(velMsg.Twist.Twist.Linear.X.^2 + velMsg.Twist.Twist.Linear.Y.^2);
currentVel = currentVel * v * 10;
end
currentDir = v * 10;
%continue
currentPose = getPose(gpsSub, imuSub)';
currentPose(1) = currentPose(1) - 0.5*cos(currentPose(3));
currentPose(2) = currentPose(2) - 0.5*sin(currentPose(3));
theta = currentPose(3);
currentPose(3)= rad2deg(currentPose(3));
end
% Update driving direction for the simulator. If the vehicle changes
% driving direction, reset and return the current vehicle velocity as zero.
%currentVel = updateDrivingDirection(vehicleSim, direction, currentDir);
% if currentPose(3) <0
% currentPose(3) = 180- currentPose(3);
% end
% Compute steering command.
steeringAngle = lateralControllerStanley(refPose, currentPose, currentVel, ...
Direction=direction, Wheelbase=vehicleDims.Wheelbase);
% Compute acceleration and deceleration commands.
%lonController.Direction = direction;
% [accelCmd, decelCmd] = lonController(refVel, currentVel);
% v = v* 0.5 + accelCmd + decelCmd;
w = deg2rad(steeringAngle);
%w = v * tan(w);
if w > 0.4
w = 0.4;
elseif w < -0.4
w = -0.4;
end
if v <0 && v >-0.15
v= -0.15;
end
[pub, msg] = publish_twist_command(v, w, '/cmd_vel');
send(pub, msg);
%isGoalReached = sqrt(sum((currentPose(1:2)-parkPose(1:2)).^2)) < 0.5;
isGoalReached = currentPose(2)<parkPose(2);
% Check if the vehicle reaches the goal.
%isGoalReached = sqrt(sum((currentPose(1:2)-parkPose(1:2)).^2)) < 0.3;
%helperGoalChecker(parkPose, currentPose, currentVel, 0, direction);
% Get current pose and velocity of the vehicle.
%currentPose = getVehiclePose(vehicleSim);
velMsg = receive(velSub);
currentVel = sqrt(velMsg.Twist.Twist.Linear.X.^2 + velMsg.Twist.Twist.Linear.Y.^2);
% 차량이 향하는 방향의 단위 벡터
directionVector = [cos(theta), sin(theta)]; % z 방향은 0으로 가정
% 위치 변화량 (deltaX, deltaY, deltaZ)
positionChange = [velMsg.Twist.Twist.Linear.X, velMsg.Twist.Twist.Linear.Y];
% 전진 또는 후진 결정
dotProduct = dot(directionVector, positionChange);
currentVel = currentDir * currentVel;
toc
end
[pub, msg] = publish_twist_command(0, 0, '/cmd_vel');
send(pub, msg);
%%
function vehiclePose = getPose(gpsSub, imuSub)
gpsMsg = receive(gpsSub);
imuMsg = receive(imuSub);
quat = [imuMsg.Orientation.W, imuMsg.Orientation.X, imuMsg.Orientation.Y, imuMsg.Orientation.Z];
euler = quat2eul(quat);
yaw = euler(1);
vehiclePose = [gpsMsg.Pose.Pose.Position.X;gpsMsg.Pose.Pose.Position.Y;yaw];
end
function [pub, msg] = publish_twist_command(v, w, topicName)
pub = rospublisher(topicName, 'geometry_msgs/Twist','DataFormat','struct');
msg = rosmessage(pub);
msg.Linear.X = v;
msg.Angular.Z = w;
end
function roiPtCloud = preprocess_lidar_data(lidarData, params, roi)
xyzData = rosReadXYZ(lidarData);
ptCloud = pointCloud(xyzData);
ptCloudOrg = pcorganize(ptCloud, params);
groundPtsIdx = segmentGroundFromLidarData(ptCloudOrg);
nonGroundPtCloud = select(ptCloudOrg, ~groundPtsIdx, 'OutputSize', 'full');
indices = findPointsInROI(nonGroundPtCloud, roi);
roiPtCloud = select(nonGroundPtCloud, indices);
roiPtCloud = pcdenoise(roiPtCloud, 'PreserveStructure', true);
end
function odomWaypoints = transformWaypointsToOdom(waypoints, vehiclePoseInOdom)
% Initialize transformed waypoints
odomWaypoints = zeros(size(waypoints));
% Extract the vehicle's yaw angle
theta = vehiclePoseInOdom(3);
% Create the 2D rotation matrix
R = [cos(theta), -sin(theta);
sin(theta), cos(theta)];
% Transform each waypoint
for i = 1:size(waypoints,1)
% Rotate the waypoint considering the vehicle's yaw
rotatedPoint = R * waypoints(i,:)';
% Translate considering the vehicle's position in the odom frame
odomWaypoints(i,:) = rotatedPoint' + vehiclePoseInOdom(1:2)';
end
end
일단 전체 코드이고 천천히 설명하겠습니다.
주차 표지판을 보면 실행되는 코드이고, 아직 주차 표지판을 학습하지 못해서 라이다 상 물체가 잡히면 실행되도록 되어 있습니다.
라이다 상 물체가 잡히면 차량은 속도를 확 줄이고, 차량 우측에 콘을 잡아냅니다. 콘이 일정하게 가다가 콘 사이의 거리가 4미터 이상이 되면 그 곳이 주차 지점이라고 판단하고 멈추게 됩니다. 4미터가 떨어진 콘 중간의 중간 좌표에 우측으로 1.5미터 가게 되면 최종 주차 지점이 형성됩니다.
빨간 점이 콘을 인지하고, 박스를 쳐서 4개의 꼭짓점이고, 초록색 점이 제가 주차를 진행할 좌표가 됩니다.
그럼 이제 콘을 인지했으니 주차를 위한 알고리즘을 시작하게 됩니다.
인지된 콘으로 costmap을 만들고, Reeds Shepp을 활용하여 콘에 부딪히지 않게 경로를 형성하게 됩니다.
경로는 차량의 길이, 너비, 최소 회전반경을 기준으로 형성됩니다.
저 직사각형보다 차가 훨씬 작아서 차량이 부딛히지 않는 경로입니다 ㅎㅎ...
그 이후 횡 방향 컨트롤러로 스텐리를 사용하여 경로를 추종합니다.
이건 다른 영상이긴 한데 주차에 성공한 영상입니다.
초반에 오랜시간 matlab에서 계산하는 과정은 컴퓨팅 속도가 차량속도를 따라잡지 못해서 생기는 오류 때문에 회전반경을 크게 해놔서 경로 생성이 오래걸리는 것 때문에 조금 걸리나 지금은 해결해서 3~10초면 생성합니다.
728x90
'자율주행 자동차' 카테고리의 다른 글
자율 주행 자동차 장애물 탐지 및 회피 - TEB_Local_Planner (1) | 2024.04.01 |
---|---|
AEB 관련 자료 수집 (0) | 2024.04.01 |
주차 알고리즘 - 인지,판단,제어 종합 (0) | 2024.02.06 |
주차 알고리즘 - erp 평행주차 (0) | 2024.01.30 |
주차 알고리즘 matlab (53) | 2024.01.30 |