22年暑假实习过程中第一个开发任务,基于激光雷达实现三边定位功能
开发平台为ubuntu 18.04 + ros melodic
日期:2022.7.27
本次实现:在能对拟定圆心数据进行保存和读取之后,本次将用上一次保存的数据作为目标数据,再将激光雷达换位置后的当前数据与其进行匹配,从当前的五个反光柱中找出需要的三个目标反光柱。匹配的原理是将预先录入系统的反光柱之间的边长一一去和当前能识别到的反光柱之间的边长匹配,识别出目标反光柱。并返回目标反光柱的坐标以便后期进行三边定位算法实现。
(一)代码编写
编写反光柱匹配函数,传入当前识别到的反光柱数据与保存的目标反光柱坐标数据,分别求点与点之间的距离关系,再将两组距离去进行匹配,当距离匹配成功后再将这段距离两端的坐标记录进一个数组,当数组内该坐标出现且仅出现两次时,判断为目标反光柱,并进行标注。最后返回筛选出来的目标反光柱坐标。
-
//反光柱匹配
-
void reflectorMatching(std::vector< Point > circle,std::vector< std::pair< float, float > > preservation,std::vector< std::pair< float, float > > &matching_coordinates){
-
std ::vector<float> distance_coordinate; //保存的各个坐标之间的距离
-
std ::vector<Distance> distance_circle; //当前各个反光柱之间的距离
-
std ::vector<float> matching; //匹配的反光柱编号
-
std::pair< float, float > matching_circle; //匹配的反光柱坐标
-
std::set<long> matching_num; //
-
Distance dis_circle;
-
float x_ij;
-
float y_ij;
-
float distance_ij;
-
distance_coordinate.clear();
-
distance_circle.clear();
-
for(long i = 1; i < preservation.size() ; i++){ //遍历记录的坐标距离
-
for(long j = 0;j < i;j++){
-
if(i == j){
-
continue;
-
} else {
-
x_ij = fabs(preservation[j].first - preservation[i].first);
-
y_ij = fabs(preservation[j].second - preservation[i].second);
-
distance_ij = sqrt(pow(x_ij, 2) + pow(y_ij, 2));
-
distance_coordinate.push_back(distance_ij);
-
}
-
}
-
}
-
for(long i = 1; i < circle.size() ; i++){ //遍历当前各个反光柱圆心的坐标距离
-
for(long j = 0;j < i;j++){
-
if(i == j){
-
continue;
-
} else {
-
x_ij = fabs(circle[j].x - circle[i].x);
-
y_ij = fabs(circle[j].y - circle[i].y);
-
distance_ij = sqrt(pow(x_ij, 2) + pow(y_ij, 2));
-
dis_circle.distance = distance_ij;
-
dis_circle.one = i;
-
dis_circle.two = j;
-
distance_circle.push_back(dis_circle);
-
}
-
}
-
}
-
for(long i = 0;i < distance_circle.size();i++){ //匹配记录的和当前的坐标距离
-
// std::cout << "当前匹配距离:" << distance_circle[i].distance << std:: endl;
-
for(long j = 0;j < distance_coordinate.size();j++){
-
// std::cout << "预设匹配距离:" << distance_coordinate[j]<< std:: endl;
-
if(abs(distance_coordinate[j] - distance_circle[i].distance) < 0.02) { //匹配误差 0.02 m
-
// std::cout << "能匹配上" << j <<std:: endl;
-
matching.push_back(distance_circle[i].one);
-
matching.push_back(distance_circle[i].two);
-
}
-
}
-
}
-
for(int i=0;i<matching.size();i++) { //去除重复编号
-
matching_num.insert(matching[i]);
-
}
-
for(std::set<long>::iterator it=matching_num.begin();it!=matching_num.end();it++) {
-
std::cout << "匹配成功,编号:" << *it<< std::endl;
-
std::cout << "x轴:"<<circle[*it].x << "y轴:"<<circle[*it].y << std::endl;
-
if(count(matching.begin(), matching.end(), *it) == 2){ //当单个反光柱被作为顶点时编号会出现两次 才匹配上
-
set_matching_marker_property(circle[*it].x ,circle[*it].y,*it); //发布匹配标记
-
matching_circle.first = circle[*it].x ;
-
matching_circle.second = circle[*it].x ;
-
matching_coordinates.push_back(matching_circle); //记录匹配上的反光柱坐标
-
} else {
-
ROS_WARN("Match failed!!!");
-
}
-
}
-
}
新增匹配标记函数,与反光柱标记函数类似,区别在于颜色与透明度,最后的持续时间新加为0.5s,防止匹配标记停留。
-
// 设置匹配标记并发布
-
void set_matching_marker_property(float mx,float my,long n){
-
/*决定从哪个视图可以看到标记r*/
-
marker_.header.frame_id = "laser_frame";
-
marker_.ns = "sign2";
-
marker_.id = n;
-
//设置标记类型:圆柱体
-
marker_.type = visualization_msgs::Marker::CYLINDER;
-
//设置标记坐标
-
marker_.pose.position.x = mx;
-
marker_.pose.position.y = my;
-
marker_.pose.position.z = 0;
-
//设置标记尺寸
-
marker_.scale.x = 0.2; //m
-
marker_.scale.y = 0.2;
-
marker_.scale.z = 0.2;
-
//设置标记颜色
-
marker_.color.a = 0.5; // Don't forget to set the alpha!
-
marker_.color.r = 0.0;
-
marker_.color.g = 1.0;
-
marker_.color.b = 0.0;
-
//设置标记动作
-
marker_.action = visualization_msgs::Marker::ADD;
-
marker_.lifetime = ros::Duration(0.5); //0.5s后消失,输入0时为不消失
-
Publish();//发布
-
};
修改处理激光信息函数。
-
//处理激光信息
-
void scan_CB(sensor_msgs::LaserScan scan) {
-
std::vector< Outline > outlines; //
-
std::vector< Point > circle; //当前反光柱数据
-
std::vector< std::pair< float, float > > preservation_coordinates; //保存的反光柱坐标
-
std::vector< std::pair< float, float > > matching_coordinates; //匹配的反光柱坐标
-
std::string fileaddress = "/home/ding/test_ws/src/HAL/trilateration/src/CircleData.txt"; //反光柱坐标数据文件地址
-
bool fileoperation_state = false; //true; //文件读写标志为,true为写,false为读
-
for (int i = 0; i < 5; i++) {
-
circle = findCircle(scan); //获取各个反光柱圆心
-
}
-
fileOperation(fileaddress,circle,preservation_coordinates,fileoperation_state); //对获取的反光柱数据进行读写文件处理
-
if(!fileoperation_state){
-
reflectorMatching(circle,preservation_coordinates,matching_coordinates); //读文件状态下 保存的数据与当前的数据进行匹配
-
}
-
}
(二)运行结果
匹配成功—五选三
匹配失败—不生成绿色匹配标记
(三)问题和下一目标
问题:目前仅能简单识别出反光柱,当目前反光柱数量增加时是否会出现错误还不知道,且当反光柱距离较远时,可能会出现匹配不上的情况。
目标:根据最后拿到的目标反光柱坐标进行三边定位和坐标变换,求出激光雷达(即机器人)在全局之中的坐标。