超维空间S2无人机使用说明书——52、初级版——使用PID算法进行基于yolo的目标跟踪

引言:在实际工程项目中,为了提高系统的响应速度和稳定性,往往需要采用一定的控制算法进行目标跟踪。这里抛砖引玉,仅采用简单的PID算法进行目标的跟随控制,目标的识别依然采用yolo。对系统要求更高的,可以对算法进行改进,也欢迎读者与我们联系,合作开发。

步骤一:打开摄像头

注意:为了获取目标物的三维位置信息,我们采用了D435深度摄像头,仅供参考,可根据需要自行选择即可

javascript 复制代码
roslaunch realsense2_camera rs_camera.launch

查看话题,需要/camera/color/image_raw和/camera/depth/image_rect_raw

步骤二:打开yolo识别节点,具体yolo版本可以根据需要选择

javascript 复制代码
 roslaunch darknet_ros darknet_ros.launch 

没有报错的情况下,会弹出识别效果图,如下:

## 注:我这里训练的是自己打印的H型地标,具体可以根据需要选择合适的目标物

步骤三:打开三维坐标转换节点

该节点可以直接一话题的形式输出目标物的名称和真实的位置信息

javascript 复制代码
roslaunch darknet_real_position darknet_real_position.launch

launch文件解析

此处的launch文件,以参数的方式指定了识别目标。比如landing,因此这个节点只会把指定的landing地标位置信息打印出来,其他的目标通通忽略

查看话题数据/object_position

从上述图片可以看出,系统非常准确的给出了目标物的名称和真实的位置信息,单位是米。需要指出的是,这里的位置是相对于D435摄像头的位置信息,X表示横向位置,Y表示纵向位置,Z表示实际的距离信息

步骤四:启动PID跟随节点。注意,可以先不要启动mavros,仅仅测试PID控制器发布出的速度是否正确。在确认了没问题后在启动mavros节点,无人机就可以进行正常的跟随运动了

javascript 复制代码
roslaunch follow_pid follow_pid.launch 

launch文件解析

这里仅仅进行偏航角度和距离的控制,如果需要对高度方向控制。可以直接复制代码进行简单的修改即可。参数linear_x_p和linear_x_d是距离的PID控制,同理yaw_rate_p和yaw_rate_d是角度的控制。参数target_x_angle是期望保持的角度,通常设置为0即可。最后参数target_distance是期望保持的距离,单位是毫米

代码如下:

javascript 复制代码
#include <ros/ros.h>
#include <std_msgs/Bool.h>
#include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/TwistStamped.h>
#include <mavros_msgs/CommandBool.h>
#include <mavros_msgs/SetMode.h>
#include <mavros_msgs/State.h>
#include <mavros_msgs/PositionTarget.h>
#include <cmath>
#include <tf/transform_listener.h>
#include <nav_msgs/Odometry.h>
#include <mavros_msgs/CommandLong.h>   
#include <string>

#define MAX_ERROR 0.20
#define VEL_SET   0.10
#define ALTITUDE  0.40

using namespace std;


float target_x_angle = 0;
float target_distance = 2000;
float linear_x_p = 0.5;
float linear_x_d = 0.33;
float yaw_rate_p = 4.0;
float yaw_rate_d = 15;

geometry_msgs::PointStamped object_pos; 
nav_msgs::Odometry local_pos;
mavros_msgs::State current_state;  
mavros_msgs::PositionTarget setpoint_raw;
//检测到的物体坐标值
string current_frame_id   = "no_object";
double current_position_x = 0;
double current_position_y = 0;
double current_distance   = 0;

//1、订阅无人机状态话题
ros::Subscriber state_sub;

//2、订阅无人机实时位置信息
ros::Subscriber local_pos_sub;

//3、订阅实时位置信息
ros::Subscriber object_pos_sub;

//4、发布无人机多维控制话题
ros::Publisher  mavros_setpoint_pos_pub;

//5、请求无人机解锁服务        
ros::ServiceClient arming_client;

//6、请求无人机设置飞行模式,本代码请求进入offboard
ros::ServiceClient set_mode_client;

void pid_control()
{
		static float last_error_x_angle = 0;
		static float last_error_distance = 0;				
		float x_angle;
		float distance;

		if(current_position_x == 0 && current_position_y == 0 && current_distance == 0)
		{
			x_angle  = target_x_angle;
			distance = target_distance;
		}
		else
		{
			x_angle = current_position_x / current_distance;
			distance = current_distance;
		}
		
		float error_x_angle = x_angle - target_x_angle;
		float error_distance = distance - target_distance;
		if(error_x_angle > -0.01 && error_x_angle < 0.01)  
		{
			error_x_angle = 0;
		}
		if(error_distance > -80 && error_distance < 80) 
		{
			error_distance = 0;
		}

		setpoint_raw.velocity.x = error_distance*linear_x_p/1000 + (error_distance - last_error_distance)*linear_x_d/1000;
		if(setpoint_raw.velocity.x < -0.3)  
		{
			setpoint_raw.velocity.x = -0.3;
		}
		else if(setpoint_raw.velocity.x > 0.3) 
		{
			setpoint_raw.velocity.x = 0.3;	
		}
		
		setpoint_raw.yaw_rate = error_x_angle*yaw_rate_p + (error_x_angle - last_error_x_angle)*yaw_rate_d;
		if(setpoint_raw.yaw_rate < -0.5)  
		{
			setpoint_raw.yaw_rate = -0.5;
		}
		else if(setpoint_raw.yaw_rate > 0.5) 
		{
			setpoint_raw.yaw_rate = 0.5;
		}
		mavros_setpoint_pos_pub.publish(setpoint_raw);
		last_error_x_angle  = error_x_angle;
		last_error_distance = error_distance;
}

 
void state_cb(const mavros_msgs::State::ConstPtr& msg)
{
    current_state = *msg;
}

void local_pos_cb(const nav_msgs::Odometry::ConstPtr& msg)
{
    local_pos = *msg;
}

void object_pos_cb(const geometry_msgs::PointStamped::ConstPtr& msg)
{
	object_pos = *msg;
	current_position_x = object_pos.point.x*(-1000);
    current_position_y = object_pos.point.y*(-1000);
    
    //此处将距离由单位米改称毫米,方便提高控制精度
	current_distance   = object_pos.point.z*1000;
	current_frame_id   = object_pos.header.frame_id; 
	pid_control();	 
	//ROS_INFO("current_position_x = %f",current_position_x);
	//ROS_INFO("current_position_y = %f",current_position_y);
	//ROS_INFO("current_distance = %f"  ,current_distance);
}


int main(int argc, char *argv[])
{

    ros::init(argc, argv, "follow_pid");
    
    ros::NodeHandle nh;

	state_sub     = nh.subscribe<mavros_msgs::State>("mavros/state", 100, state_cb);
		
    local_pos_sub = nh.subscribe<nav_msgs::Odometry>("/mavros/local_position/odom", 100, local_pos_cb);
    
    object_pos_sub = nh.subscribe<geometry_msgs::PointStamped>("object_position", 100, object_pos_cb);
		
    mavros_setpoint_pos_pub = nh.advertise<mavros_msgs::PositionTarget>("/mavros/setpoint_raw/local", 100);   
		               
	arming_client = nh.serviceClient<mavros_msgs::CommandBool>("mavros/cmd/arming");
		
	set_mode_client = nh.serviceClient<mavros_msgs::SetMode>("mavros/set_mode");

    ros::Rate rate(20.0); 

	ros::param::get("linear_x_p",linear_x_p);
	ros::param::get("linear_x_d",linear_x_d);
	ros::param::get("yaw_rate_p",yaw_rate_p);
	ros::param::get("yaw_rate_d",yaw_rate_d);
	
	ros::param::get("target_x_angle", target_x_angle);
	ros::param::get("target_distance",target_distance);


	 //等待连接到PX4无人机
   /* while(ros::ok() && current_state.connected)
    {
        ros::spinOnce();
        rate.sleep();
    }*/

    setpoint_raw.type_mask = /*1 + 2 + 4 + 8 + 16 + 32*/ + 64 + 128 + 256 + 512 /*+ 1024 + 2048*/;
	setpoint_raw.coordinate_frame = 1;
	setpoint_raw.position.x = 0;
	setpoint_raw.position.y = 0;
	setpoint_raw.position.z = 0 + ALTITUDE;
	mavros_setpoint_pos_pub.publish(setpoint_raw);
 
    for(int i = 100; ros::ok() && i > 0; --i)
    {
		mavros_setpoint_pos_pub.publish(setpoint_raw);
        ros::spinOnce();
        rate.sleep();
    }
    
    //请求offboard模式变量
    mavros_msgs::SetMode offb_set_mode;
    offb_set_mode.request.custom_mode = "OFFBOARD";
 
    //请求解锁变量
    mavros_msgs::CommandBool arm_cmd;
    arm_cmd.request.value = true;

    ros::Time last_request = ros::Time::now();
    //请求进入offboard模式并且解锁无人机,15秒后退出,防止重复请求       
    /*while(ros::ok())
    {
    	//请求进入OFFBOARD模式
        if( current_state.mode != "OFFBOARD" && (ros::Time::now() - last_request > ros::Duration(5.0)))
        {
            if( set_mode_client.call(offb_set_mode) && offb_set_mode.response.mode_sent)
            {
                ROS_INFO("Offboard enabled");
            }
           	last_request = ros::Time::now();
       	}
        else 
		{
			//请求解锁
			if( !current_state.armed && (ros::Time::now() - last_request > ros::Duration(5.0)))
			{
		        if( arming_client.call(arm_cmd) && arm_cmd.response.success)
		       	{
		            ROS_INFO("Vehicle armed");
		        }
		        	last_request = ros::Time::now();
			}
		}
	    if(ros::Time::now() - last_request > ros::Duration(15.0))
	    	break;
		mavros_setpoint_pos_pub.publish(setpoint_raw);
        ros::spinOnce();
        rate.sleep();
    }*/   
	
	while(ros::ok())
	{

		//ROS_INFO("11111");
		ros::spinOnce();
		rate.sleep();

	}

}

步骤五:在上述基础上再打开mavros,即可开始跟随控制。代码后续会在B站进行讲解。同时会提供相应的实机演示。链接会在后续给出。

相关推荐
qq_463408422 分钟前
React Native跨平台技术在开源鸿蒙中使用WebView来加载鸿蒙应用的网页版或通过一个WebView桥接本地代码与鸿蒙应用
javascript·算法·react native·react.js·开源·list·harmonyos
Jul1en_2 分钟前
【算法】位运算
算法
苏州知芯传感7 分钟前
柔性抓取的“慧眼”:MEMS 3D视觉如何让机器人精准识别无序堆叠的复杂钣金件?
算法·3d·机器人·mems
iAkuya15 分钟前
(leetcode)力扣100 22相交链表(双指针)
算法·leetcode·链表
山梨一碗粥23 分钟前
YOLO的发展
yolo
chao18984425 分钟前
基于MATLAB的ADI方法求解偏微分方程详解
开发语言·算法·matlab
智驱力人工智能30 分钟前
超越识别 将光学字符识别(OCR)技术转化为可靠业务能力的交付思维 光学字符识别 金融票据OCR识别系统 物流单据自动识别技术
人工智能·opencv·算法·目标检测·ocr·边缘计算
算法与编程之美41 分钟前
解决tensor的shape不为1,如何转移到CPU的问题
人工智能·python·深度学习·算法·机器学习
natide41 分钟前
词汇/表达差异-8-Token Overlap(词元重叠度)
大数据·人工智能·深度学习·算法·自然语言处理·nlp·知识图谱
hetao17338371 小时前
2025-12-22 hetao1733837的笔记
c++·笔记·算法