基于ROS、C++开发中使用的微分算法

使用前需要下载并导入opencv库,进行如下定义:

分别对应3维和2维的数组微分。

#include <map>
#include<std_msgs/Float64MultiArray.h>
#include<deque>
//#include<你的opencv位置>


struct PositionInfo{
  cv::Point3f position;
  cv::Point2f ax_ay;
  ros::Time timestamp;
};
// 定义用于存储上一帧中每个二维码的位置和时间戳的映射
std::map<int, cv::Point2f> last_positions;
std::map<int, ros::Time> last_timestamps;
std::map<int, cv::Point3f> last_positions_3d;
std::map<int, std::deque<PositionInfo>>position_history_map;

一、微分方法

下面介绍三种常见微分方法封装成的函数。

一.普通微分

优点:简单快捷。

缺点:误差较大。

void computeDif(int id, const cv::Point3f& position, const cv::Point2f& ax_ay, const ros::Time& time) {
    // 检查是否有前一个时间点的数据
    if (last_timestamps.find(id) != last_timestamps.end()) {
        // 计算时间间隔
        double time_interval = (time - last_timestamps[id]).toSec();

        if (time_interval > 0) {
            // 计算位置和角度的变化
            cv::Point3f pos_change = position - last_positions_3d[id];
            cv::Point2f ax_ay_change = ax_ay - last_ax_ay[id];

            // 计算速度
            speed_x = pos_change.x / time_interval;
            speed_y = pos_change.y / time_interval;
            speed_z = pos_change.z / time_interval;

            speed_ax = ax_ay_change.x / time_interval;
            speed_ay = ax_ay_change.y / time_interval;
        }
    }

    // 更新最后的位置、角度和时间戳
    last_positions_3d[id] = position;
    last_ax_ay[id] = ax_ay;
    last_timestamps[id] = time;
}

二、使用前三项的均值与后三项的均值微分

优点:误差在无噪声等外界干扰时会减小

缺点:受噪声影响大

void computeDif(int id,const cv::Point3f& position,const cv::Point2f& ax_ay,const ros::Time& time){
  auto& history = position_history_map[id];
  history.push_back({position,ax_ay,time});
  //history.push_back({ax_ay,time});

  if(history.size()>=6){
    cv::Point3f first_three_pos(0,0,0);
    cv::Point3f last_three_pos(0,0,0);
    cv::Point2f first_three_ax_ay(0,0);
    cv::Point2f last_three_ax_ay(0,0);

    for(int i = 0;i<3;++i){
      first_three_pos += history[i].position;
      last_three_pos += history[i+3].position;
      first_three_ax_ay += history[i].ax_ay;
      last_three_ax_ay += history[i+3].ax_ay;
    }

    first_three_pos *= (1.0/3);
    last_three_pos *= (1.0/3);
    first_three_ax_ay *= (1.0/3);
    last_three_ax_ay *= (1.0/3);

    cv::Point3f pos_change = last_three_pos-first_three_pos;
    cv::Point2f ax_ay_change = last_three_ax_ay - first_three_ax_ay;
    double time_interval = (history[5].timestamp - history[0].timestamp).toSec();

    if(time_interval >  0){
      speed_x = pos_change.x/time_interval;
      speed_y = pos_change.y/time_interval;
      speed_z = pos_change.z/time_interval;

      speed_ax = ax_ay_change.x/time_interval;
      speed_ay = ax_ay_change.y/time_interval;
    }

    history.pop_front();
  }
  last_positions_3d[id] = position;
  last_ax_ay[id] = ax_ay;
  last_timestamps[id] = time;
}

三、数值微分中的三项前向微分

void computeDif(int id, const cv::Point3f& position, const cv::Point2f& ax_ay, const ros::Time& time){
    auto& history = position_history_map[id];
    history.push_back({position, ax_ay, time});

    if (history.size() >= 3) {
        double h = (history[2].timestamp - history[1].timestamp).toSec();
        //double h2 = (history[1].timestamp - history[0].timestamp).toSec();

        if (h > 0 ) {
            
            cv::Point3f diff_pos = (-3 * history[0].position + 4 * history[1].position - history[2].position) / (2 * h);

           
            cv::Point2f diff_ax_ay = (-3 * history[0].ax_ay + 4 * history[1].ax_ay - history[2].ax_ay) / (2 * h);

            
            speed_x = diff_pos.x;
            speed_y = diff_pos.y;
            speed_z = diff_pos.z;
            speed_ax = diff_ax_ay.x;
            speed_ay = diff_ax_ay.y;
        }

        history.pop_front();
    }

    last_positions_3d[id] = position;
    last_ax_ay[id] = ax_ay;
    last_timestamps[id] = time;
}

属于比较高级的数值微分方法,使用这种方法可以抑制噪声,并且得到的结果误差很小。

如果结果依然不够理想,可以加入滤波,下面是一个一阶低通滤波的示例:

float alpha = 0.5; // 选择一个适当的alpha值,需要根据实际情况调整

// 为每个速度分量初始化滤波后的历史值
float filtered_speed_x = 0;
float filtered_speed_y = 0;
float filtered_speed_z = 0;

void lowPassFilter(float& filtered_speed,float new_speed){
  filtered_speed = alpha*new_speed+(1-alpha)*filtered_speed;
}

二.函数调用

在主函数的循环里进行调用:

          int id = tgts.targets[i].tracked_id;
          cv::Point3f current_position_3d(tgts.targets[i].px,tgts.targets[i].py,tgts.targets[i].pz);
          cv::Point2f current_ax_ay(tgts.targets[i].los_ax,tgts.targets[i].los_ay);
          ros::Time current_time = ros::Time::now();

          computeDif(id,current_position_3d,current_ax_ay,current_time);
          //滤波函数调用同理


总结

以上简单提供了三种微分方法的实现流程,可以根据自己需要进行修改。

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值