/***************************************************************************************************************************
*
* Author: bingo
* Email: 1554459957@qq.com
* Time: 2019.10.14
* Description: lidar collision vfh v1.0
*
***************************************************************************************************************************/
//ROS 头文件
#include <ros/ros.h>
#include <Eigen/Eigen>
#include <cmath>
#include <algorithm>
#include <vector>
//topic 头文件
#include <iostream>
#include<stdio.h>
#include <std_msgs/Bool.h>
#include <mavros_msgs/State.h>
#include <geometry_msgs/Pose.h>
#include <sensor_msgs/LaserScan.h>
#include <geometry_msgs/PoseStamped.h>
#include <mavros_msgs/PositionTarget.h>
#include <eigen_conversions/eigen_msg.h>
#include <mavros/frame_tf.h>
#include <mavros_msgs/WaypointList.h>
#include <std_msgs/Float64.h>
#include <mavros_msgs/HomePosition.h>
#include <GeographicLib/Geocentric.hpp>
#include <sensor_msgs/NavSatFix.h>
#include "tf/transform_datatypes.h"//转换函数头文件
#include <nav_msgs/Odometry.h>//里程计信息格式
using namespace std;
#define PI 3.1415926
struct Point2D
{
float x;
float y;
float z;
};
float scan_distance_max;
float scan_distance_min;
float angle_resolution;
float heading;
float sector_value;
float sector_scale;
Point2D Uavp;
vector<float> map_cv;
vector<double> ranges;
float desire_z = 1.5; //期望高度
uint32_t init_mask = 0;
Eigen::Vector3d vel_sp_body;
void SetUavPosition(Point2D& uav) {
Uavp.x = uav.x;
Uavp.y = uav.y;
Uavp.z = uav.z;
}
void SetUavHeading(float hd) {
heading = hd;
heading += 270;
heading = (int)heading % 360;
heading = 360 - heading;
}
void ComputeMV(vector<float> r) {
float dist[360] = { 0 };
ranges.clear();
map_cv.clear();
int range_size = r.size(); //有多少条激光
for (size_t i = 0; i < range_size; i++)
{
//A non-zero value (true) if x is a NaN value; and zero (false) otherwise.
//isinf A non-zero value (true) if x is an infinity; and zero (false) otherwise.
if (!std::isnan(r[i]) && !std::isinf(r[i]))//取出有效值
{
float scan_distance = r[i];
int sector_index = std::floor((i*angle_resolution) / sector_value);//(i*1)/30 sector_index:[1 12]
if (scan_distance >= scan_distance_max || scan_distance < scan_distance_min)
scan_distance = 0;
else
scan_distance = scan_distance_max - scan_distance;
dist[sector_index] += scan_distance;
}
ranges.push_back(r[i]);
}
for (int j = 0; j < (int)(360 / sector_value); j++)//把uav四周分为12个sector,每个sector的值越小,代表越安全。
{
map_cv.push_back(dist[j]);
// printf("dist[%d]=%f-",j,dist[j]);
}
// printf("##############################################################################################\n");
}
/*检测前方[340 360],[0 20]范围内是否安全*/
bool IsFrontSafety()
{
float goal_sector = (int)(0 - (sector_value - sector_scale) + 360) % 360;//(0-(30-10)+360)%360 = 340,goal_sector = 340
int start_index = goal_sector / angle_resolution;//start_index = 340
float scan_distance = 0;
for (int i = 0; i < (sector_value - sector_scale) * 2 / angle_resolution; i++)//for(i=0;i<40;i++)
{
int real_index = (start_index + i) % (int)(360 / angle_resolution);
if (!std::isnan(ranges[real_index]) && !std::isinf(ranges[real_index]))
{
if (ranges[real_index] < scan_distance_max && ranges[real_index] >= scan_distance_min)
scan_distance = scan_distance_max - ranges[real_index] + scan_distance;
}
}
if (scan_distance < 0.1)
{
return true;
}
return false;
}
/*输入期望坐标点,输出期望机头方向*/
float CalculDirection(Point2D& goal) {
float ori;
//Compute arc tangent with two parameters
//return Principal arc tangent of y/x, in the interval [-pi,+pi] radians.
//One radian is equivalent to 180/PI degrees.
float G_theta = atan2((goal.y - Uavp.y), (goal.x - Uavp.x));
float goal_ori = G_theta * 180 / PI; //目标点相对uav的方向信息,即与y轴的夹角,正值代表在第一三现象,负值代表在二四现象。ENU坐标系下
if (goal_ori < 0)
{
goal_ori += 360;
}
goal_ori -= heading;
goal_ori += 360;
goal_ori = (int)goal_ori % 360; //把目标点方向转化成机体坐标系下的方向
float goal_sector = (int)(goal_ori - sector_value + 360) % 360;
int start_index = goal_sector / angle_resolution;
float scan_distance = 0;
for (int i = 0; i < sector_value * 2 / angle_resolution; i++)
{
int real_index = (start_index + i) % (int)(360 / angle_resolution);
if (!std::isnan(ranges[real_index]) && !std::isinf(ranges[real_index]))
{
if (ranges[real_index] < scan_distance_max && ranges[real_index] >= scan_distance_min)
scan_distance = scan_distance_max - ranges[real_index] + scan_distance;
}
}
if (scan_distance < 0.1)//判断目标方向处是否安全
{
ori = goal_ori;
ori += heading;
ori = (int)ori % 360;
return ori;//若安全,则把机头指向目标处
}
vector<int> mesh;
for (int i = 0; i < map_cv.size(); i++) //确定栅格中CV值 共有12个栅格,CV值越大,存在障碍物可能性越大
{
if (map_cv[i] < 0.1)
mesh.push_back(0);
else if (map_cv[i] >= 0.1 && map_cv[i] < 0.3)
mesh.push_back(2);
else
mesh.push_back(4);
}
vector<float> cand_dir;
for (int j = 0; j < mesh.size(); j++)
{
if (j == mesh.size() - 1) //if(j == 11)
{
if (mesh[0] + mesh[mesh.size() - 1] == 0)
cand_dir.push_back(0.0);
}
else
{
if (mesh[j] + mesh[j + 1] == 0)
cand_dir.push_back((j + 1)*sector_value);//寻找安全角度,机体坐标系下;即确定波谷
}
}
if (cand_dir.size() != 0) {
vector<float> delta;
for (auto &dir_ite : cand_dir) {
float delte_theta1 = fabs(dir_ite - goal_ori);
float delte_theta2 = 360 - delte_theta1;
float delte_theta = delte_theta1 < delte_theta2 ? delte_theta1 : delte_theta2;
delta.push_back(delte_theta);
}//寻找接近目标区域的波谷
int min_index = min_element(delta.begin(), delta.end()) - delta.begin();
ori = cand_dir.at(min_index);
ori += heading;
ori = (int)ori % 360;
return ori;//确定机头方向
}
return -1;
}
mavros_msgs::State current_state;
void state_cb(const mavros_msgs::State::ConstPtr& msg) {
init_mask |= 1 << 1;
current_state = *msg;
}
mavros_msgs::HomePosition home_pos;
void home_pos_cb(const mavros_msgs::HomePosition::ConstPtr& msg) {
init_mask |= 1 << 2;
home_pos = *msg;
}
geometry_msgs::PoseStamped local_pos;
Eigen::Vector3d current_local_pos;
bool local_pos_updated = false;
void local_pos_cb(const geometry_msgs::PoseStamped::ConstPtr& msg)
{
init_mask |= 1 << 3;
current_local_pos = mavros::ftf::to_eigen(msg->pose.position);
local_pos = *msg;
Point2D pt2d;
pt2d.x = current_local_pos.x();
pt2d.y = current_local_pos.y();
SetUavPosition(pt2d);
local_pos_updated = true;
}
/*
mavros_msgs::WaypointList waypoints;
void waypoints_cb(const mavros_msgs::WaypointList::ConstPtr& msg) {
init_mask |= 1 << 4;
waypoints = *msg;
}
*/
bool scan_updated = false;
void scan_cb(const sensor_msgs::LaserScan::ConstPtr &msg)
{
//激光雷达数据回调函数
init_mask |= 1 << 5;
ComputeMV(msg->ranges);
scan_updated = true;
}
bool heading_updated = false;
void heading_cb(const std_msgs::Float64::ConstPtr &msg)
{
init_mask |= 1 << 6;
SetUavHeading(msg->data);
heading_updated = true;
}
Eigen::Vector3d current_gps;
void gps_cb(const sensor_msgs::NavSatFix::ConstPtr &msg)
{
init_mask |= 1;
current_gps = { msg->latitude, msg->longitude, msg->altitude };
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>主 函 数<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
int main(int argc, char **argv)
{
ros::init(argc, argv, "collision_avoidance_vfh");
ros::NodeHandle nh("~");
scan_distance_max = 2.1;
scan_distance_min = 0.1;
angle_resolution = 1.0;
heading = 90;
sector_value = 30;
sector_scale = 10;
Uavp.x = 0;
Uavp.y = 0;
ros::Subscriber gps_sub
VFH无人机避障算法代码移植
需积分: 0 139 浏览量
更新于2024-05-30
1
收藏 20KB ZIP 举报
VFH(Vector Field Histogram,矢量场直方图)是一种广泛应用在机器人和无人机避障中的算法,它通过构建环境的矢量场来决定移动设备的路径规划,从而避开障碍物。这种算法尤其适用于动态和复杂环境,因为它可以快速响应障碍物的变化。下面将详细介绍VFH算法的基本原理、实现步骤以及在无人机上的应用。
VFH算法的核心思想是利用传感器数据(如激光雷达或超声波传感器)获取周围环境的信息,并构建一个表示运动方向的矢量场。这个矢量场由许多小矢量组成,每个矢量代表了一个可能的运动方向及其对应的质量。质量的大小反映了在该方向上无障碍物的程度。当无人机需要规划路径时,它会选择矢量场中质量较高的方向作为移动方向,这样可以有效地避开障碍物。
在代码移植的过程中,首先需要理解VFH算法的数学模型和计算流程。算法通常包括以下几个关键步骤:
1. **数据采集**:无人机的传感器收集周围环境的数据,例如距离障碍物的距离信息。
2. **构建矢量场**:根据收集到的数据,生成一系列小矢量,每个矢量表示一个可能的运动方向。这些矢量的长度和方向代表了无人机可以安全行驶的程度。
3. **矢量场直方图**:对矢量场进行统计,形成直方图,这一步骤有助于量化各个方向的安全程度。直方图的每个bin(区间)对应一个角度,bin的值表示该角度范围内矢量的质量总和。
4. **路径规划**:选择直方图中质量最高的方向作为无人机的运动方向,这通常是最远离障碍物的方向。为了保证平滑性,还可以采用一些路径平滑策略。
5. **实时更新**:随着无人机的移动和环境的变化,矢量场和直方图需要实时更新,以确保避障的有效性。
在软件/插件的开发中,VFH算法的实现通常涉及以下几个方面:
- **数据处理模块**:这部分代码负责从传感器接收数据,将其转换为可以用于构建矢量场的格式。
- **矢量场生成模块**:根据处理后的数据,生成矢量场,并进行直方图计算。
- **路径规划模块**:根据直方图的结果,决定无人机的下一运动步长和方向。
- **控制指令输出模块**:将规划好的路径转化为无人机的实际控制指令,如电机转速和舵机角度。
- **实时更新机制**:实现算法的动态适应性,如定时更新或基于传感器变化的触发更新。
在实际的代码移植过程中,开发者需要注意以下几点:
- **兼容性**:确保代码能在目标平台(如嵌入式系统或特定的飞行控制器)上运行,这可能需要调整数据类型、内存管理、中断处理等方面。
- **性能优化**:VFH算法需要实时执行,因此需要优化代码以降低计算延迟,提高响应速度。
- **错误处理和调试**:确保代码在异常情况下能正确处理,同时设置合适的日志和调试信息,方便问题排查。
在“VFH避障代码”压缩包中,可能包含上述各模块的源代码文件,开发者需要理解每部分的功能,并根据具体需求进行修改和整合,以实现VFH算法在无人机上的高效避障功能。
![avatar](https://profile-avatar.csdnimg.cn/default.jpg!1)
![avatar-vip](https://csdnimg.cn/release/downloadcmsfe/public/img/user-vip.1c89f3c5.png)
流浪者1015
- 粉丝: 1999
- 资源: 51
最新资源
- (源码)基于Taro和TypeScript的小程序多端编译项目.zip
- 控制电机仿真实验报告:感应电动机转差型矢量控制伺服模型系统及其实验参数解析,感应电动机转差型矢量控制伺服模型系统仿真与实验报告(附参数与波形图)-matlab版本限制需注意,控制电机-感应电动机转差型
- (源码)基于Go语言的Logbud日志增强工具.zip
- 正弦波永磁同步电动机矢量控制系统仿真报告(Matlab版本2016a及以下),基于Matlab 2016a以下的正弦波永磁同步电动机矢量控制系统仿真模型与实验报告,控制电机-正弦波永磁同步电动机矢量控
- (源码)基于Python的工业环境温湿度实时监控项目.zip
- (源码)基于Arduino和传感器的自动手消毒器.zip
- (源码)基于Node.js和Express框架的电影网站管理系统.zip
- (源码)基于Arduino的摩托车光学检测器控制程序.zip
- (源码)基于Arduino的RC赛车远程控制系统升级.zip
- 基于Vue和PHP的化妆品小程序《科妮赛》设计源码
- 基于C#实现的UDP局域网文件传输demo设计源码
- (源码)基于Arduino的模拟赛车顺序换挡器.zip
- 基于Vue框架的第三方施工巡检APP JavaScript设计源码
- 基于Nodejs与Vue框架的计算机导论精品课程前端设计源码
- (源码)基于muduo网络库的简单HTTP服务器.zip
- 基于Retrofit+RxJava+MVP的简约优雅多彩主题设计源码