简介:
部署的环境在我前一篇博客:在ubuntu基于ros利用yolov8对摄像头所检测的物体发布和订阅实时位置信息-CSDN博客
部署的环境有:yolov8(负责识别物体),ros(负责通信实现发布方与订阅方),此篇博客是讲在通过pid算法和外接摄像头所给函数实现使外接摄像头使所识别置信度最大的物体保持在屏幕正中央。
pid算法:
算法分为两种,一种为开环而另一种闭环。开环算法的输入不受输出影响,而闭环算法的输入受输出影响,使输出不断接近我们所设定的期望值。而pid算法属于后者。
pid函数:
u(t) = kp [ e(t) + e(t) dt + Td ] 连续
uk = kp * + ki + kd * ( - )
P算法:
目的是为了减少测量值与期望值之差
:测量值与期望值只差
越大,P输出越大
D算法:
目的是为了抑制系统的剧烈反应(过充现象)
( - ):两次误差之差
( - )越大,D输出越大
I算法:
目的是为了追求更精确的控制,消除稳态误差。稳态误差产生的原因可能是因为控制的机器要求移动太小,没有产生精确的输出使机器移动,导致产生稳态误差。
基础代码:
int PID_value(int measure , int calcu)
{
err = measure - calcu;//误差
err_sum+= err ;//误差累加
if(err_sum > 2000)
err_sum = 2000;
if(err_sum < -2000)
err_sum = -2000;//对err_sum进行限幅
err_dif = err - last_err;//误差的差值
last_err = err;//此次误差记录为”上次误差“
return Kp*err + Ki*err_sum + Kd*err_dif;
}
ros发布方代码(python):
发布方与我之前发的博客一样。
参考:在ubuntu基于ros利用yolov8对摄像头所检测的物体发布和订阅实时位置信息-CSDN博客
ros订阅方代码(C++):
订阅方框架参考:042话题通信(C++)3_订阅方实现_Chapter2-ROS通信机制_哔哩哔哩_bilibili
#头文件
#include "ros/ros.h"
#include "/home/kirby/demo03_ws/devel/include/plumbing_pub_sub/selfmsg.h"
#include "/home/kirby/demo03_ws/src/plumbing_pub_sub/include/plumbing_pub_sub/head.h"
#include <unistd.h>
#pid函数,前文已提到
int calcu_x;
int calcu_y;
float err ;
float err_dif;
float last_err = 0;
float Kp=0.85 , Ki=0.25, Kd=0.05;
int err_sum;
int PID_value(int measure , int calcu)
{
err = measure - calcu;
err_sum+= err ;
if(err_sum > 2000)
err_sum = 2000;
if(err_sum < -2000)
err_sum = -2000;
err_dif = err - last_err;
last_err = err;
return Kp*err + Ki*err_sum + Kd*err_dif;
}
#回调函数
void doYolo(const plumbing_pub_sub::selfmsg::ConstPtr& msg){
calcu_x=msg -> x1 - msg -> x2;
calcu_y=msg -> y1 - msg -> y2;
int a = PID_value(192, calcu_x);
int b = PID_value(320, calcu_y);
#外接摄像头函数,使摄像头屏幕正中央对准物体
GimbalMove(a,b);
ROS_INFO("%d,%d,%d,%ld", static_cast<int>(msg->x1), static_cast<int>(msg->x2), static_cast<int>(msg->y1), msg->y2);
}
int main(int argc , char *argv[]){
#设置编码
setlocale(LC_ALL,"");
#初始化ros节点
ros::init(argc,argv,"yolo_sub_c");
#外接摄像头函数,使回正
GimbalReturnHome();
#实例化ros句柄
ros::NodeHandle nh;
#休眠3秒
ros::Duration(3).sleep();
#实例化订阅者对象
ros::Subscriber sub = nh.subscribe("location",10,doYolo);
ros::spin();
}
配置文件:
配置文件参考我之前发的博客。