rm_vision/tasks/auto_buff/buff_target.cpp
2025-12-15 02:33:20 +08:00

713 lines
22 KiB
C++

#include "buff_target.hpp"
namespace auto_buff
{
///voter
Voter::Voter() : clockwise_(0) {}
void Voter::vote(const double angle_last, const double angle_now)
{
if (std::abs(clockwise_) > 50) return;
if (angle_last > angle_now)
clockwise_--;
else
clockwise_++;
}
int Voter::clockwise() { return clockwise_ > 0 ? 1 : -1; }
/// Target
Target::Target() : first_in_(true), unsolvable_(true) {};
Eigen::Vector3d Target::point_buff2world(const Eigen::Vector3d & point_in_buff) const
{
if (unsolvable_) return Eigen::Vector3d(0, 0, 0);
Eigen::Matrix3d R_buff2world =
tools::rotation_matrix(Eigen::Vector3d(ekf_.x[4], 0.0, ekf_.x[5])); // pitch = 0
auto R_yaw = ekf_.x[0];
auto R_pitch = ekf_.x[2];
auto R_dis = ekf_.x[3];
Eigen::Vector3d point_in_world =
R_buff2world * point_in_buff + Eigen::Vector3d(
R_dis * std::cos(R_pitch) * std::cos(R_yaw),
R_dis * std::cos(R_pitch) * std::sin(R_yaw),
R_dis * std::sin(R_pitch));
return point_in_world;
}
bool Target::is_unsolve() const { return unsolvable_; }
Eigen::VectorXd Target::ekf_x() const { return ekf_.x; }
/// SmallTarget
SmallTarget::SmallTarget() : Target() {}
void SmallTarget::get_target(
const std::optional<PowerRune> & p, std::chrono::steady_clock::time_point & timestamp)
{
// 如果没有识别,退出函数
static int lost_cn = 0;
if (!p.has_value()) {
unsolvable_ = true;
lost_cn++;
return;
}
static std::chrono::steady_clock::time_point start_timestamp = timestamp;
auto time_gap = tools::delta_time(timestamp, start_timestamp);
// init
if (first_in_) {
unsolvable_ = true;
init(time_gap, p.value());
first_in_ = false;
}
// 处理识别时间间隔过大
if (lost_cn > 6) {
unsolvable_ = true;
tools::logger()->debug("[Target] 丢失buff");
lost_cn = 0;
first_in_ = true;
return;
}
// kalman update
unsolvable_ = false;
update(time_gap, p.value());
// 处理发散
if (std::abs(ekf_.x[6]) > SMALL_W + CV_PI / 18 || std::abs(ekf_.x[6]) < SMALL_W - CV_PI / 18) {
unsolvable_ = true;
tools::logger()->debug("[Target] 小符角度发散spd: {:.2f}", ekf_.x[6] * 180 / CV_PI);
first_in_ = true;
return;
}
}
void SmallTarget::predict(double dt)
{
// 预测下一个状态
// clang-format off
A_ << 1.0, dt, 0.0, 0.0, 0.0, 0.0, 0.0, // R_yaw
0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, // R_v_yaw
0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, // R_pitch
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, // R_dis
0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, // yaw
0.0, 0.0, 0.0, 0.0, 0.0, 1.0, dt, // roll
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0; // spd
// 过程噪声协方差矩阵 //// 调整
auto v1 = 0.001; // 角加速度方差
auto a = dt * dt * dt * dt / 4;
auto b = dt * dt * dt / 2;
auto c = dt * dt;
Q_ << a * v1, b * v1, 0.0, 0.0, 0.0, 0.0, 0.0,
b * v1, c * v1, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0;
// clang-format on
auto f = [&](const Eigen::VectorXd & x) -> Eigen::VectorXd {
Eigen::VectorXd x_prior = A_ * x;
x_prior[0] = tools::limit_rad(x_prior[0]);
x_prior[2] = tools::limit_rad(x_prior[2]);
x_prior[4] = tools::limit_rad(x_prior[4]);
x_prior[5] = tools::limit_rad(x_prior[5]);
return x_prior;
};
ekf_.predict(A_, Q_, f);
}
void SmallTarget::init(double nowtime, const PowerRune & p)
{
// 初始化内部变量
lasttime_ = nowtime;
// 初始状态协方差矩阵
x0_.resize(7);
P0_.resize(7, 7);
A_.resize(7, 7);
Q_.resize(7, 7);
H_.resize(7, 7);//z x
R_.resize(7, 7);//z z
// [R_yaw]
// [v_R_yaw]
// [R_pitch]
// [R_dis]
// [yaw]
// [angle/row]
// [spd] w=CV_PI/6
// clang-format off
// 初始状态
x0_ << p.ypd_in_world[0], 0.0, p.ypd_in_world[1], p.ypd_in_world[2],
p.ypr_in_world[0], p.ypr_in_world[2],
SMALL_W * voter.clockwise();
// 初始状态协方差矩阵
P0_ << 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 10.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-2;
// 状态转移矩阵
// A_
// 过程噪声协方差矩阵 //// 调整
// Q_
// 测量方程矩阵
// H_
// 测量噪声协方差矩阵 //// 调整
// R_
// clang-format on
// 防止夹角求和出现异常值
auto x_add = [](const Eigen::VectorXd & a, const Eigen::VectorXd & b) -> Eigen::VectorXd {
Eigen::VectorXd c = a + b;
c[0] = tools::limit_rad(c[0]);
c[2] = tools::limit_rad(c[2]);
c[4] = tools::limit_rad(c[4]);
c[5] = tools::limit_rad(c[5]);
return c;
};
// 创建扩展卡尔曼滤波器对象
ekf_ = tools::ExtendedKalmanFilter(x0_, P0_, x_add);
}
void SmallTarget::update(double nowtime, const PowerRune & p)
{
// [R_yaw] angle0
// [v_R_yaw]
// [R_pitch] angle2
// [R_dis]
// [yaw] angle4
// [angle/row] angle5
// [spd] w=CV_PI/6
const Eigen::VectorXd & R_ypd = p.ypd_in_world; // R
const Eigen::VectorXd & ypr = p.ypr_in_world;
const Eigen::VectorXd & B_ypd = p.blade_ypd_in_world; // center of blade
// 处理扇叶跳变 angle/row
if (abs(ypr[2] - ekf_.x[5]) > CV_PI / 12) {
for (int i = -5; i <= 5; i++) {
double angle_c = ekf_.x[5] + i * 2 * CV_PI / 5;
if (std::fabs(angle_c - ypr[2]) < CV_PI / 5) {
ekf_.x[5] += i * 2 * CV_PI / 5;
break;
}
}
}
// vote判断是顺时针还是逆时针旋转
voter.vote(ekf_.x[5], ypr[2]);
if (voter.clockwise() * ekf_.x[6] < 0) ekf_.x[6] *= -1; // spd
// 预测下一个状态
predict(nowtime - lasttime_);
// [R_yaw] angle0
// [R_pitch] angle1
// [R_dis]
// [angle/row] angle3
// [B_yaw] angle4
// [B_pitch] angle5
// [B_dis]
/// 1.
// [R_yaw] angle0
// [R_pitch] angle1
// [R_dis]
// [angle/row] angle3
// clang-format off
Eigen::MatrixXd H1{
{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, // R_yaw
{0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0}, // R_pitch
{0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0}, // R_dis
{0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0} // roll
};
Eigen::MatrixXd R1{
{0.01, 0.0, 0.0, 0.0}, // R_yaw
{0.0, 0.01, 0.0, 0.0}, // R_pitch
{0.0, 0.0, 0.5, 0.0}, // R_dis
{0.0, 0.0, 0.0, 0.1} // roll
};
// clang-format on
// 防止夹角求差出现异常值
auto z_subtract1 = [](const Eigen::VectorXd & a, const Eigen::VectorXd & b) -> Eigen::VectorXd {
Eigen::VectorXd c = a - b; //4 1
c[0] = tools::limit_rad(c[0]);
c[1] = tools::limit_rad(c[1]);
c[3] = tools::limit_rad(c[3]);
return c;
};
Eigen::VectorXd z1{{R_ypd[0], R_ypd[1], R_ypd[2], ypr[2]}}; // R_ypd roll
ekf_.update(z1, H1, R1, z_subtract1);
///2.
// [B_yaw] angle4
// [B_pitch] angle5
// [B_dis]
// clang-format off
Eigen::MatrixXd H2 = h_jacobian(); // 3*7
Eigen::MatrixXd R2{
{0.01, 0.0, 0.0}, // B_yaw
{0.0, 0.01, 0.0}, // B_pitch
{0.0, 0.0, 0.5} // B_dis
};
// clang-format on
// 定义非线性转换函数h: x -> z
auto h2 = [&](const Eigen::VectorXd & x) -> Eigen::Vector3d {
Eigen::VectorXd R_ypd{{x[0], x[2], x[3]}};
Eigen::VectorXd R_xyz = tools::ypd2xyz(R_ypd);
Eigen::VectorXd R_xyz_and_yr{{R_ypd[0], R_ypd[1], R_ypd[2], x[4], x[5]}};
Eigen::VectorXd B_xyz = point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.7));
Eigen::VectorXd B_ypd = tools::xyz2ypd(B_xyz);
return B_ypd;
};
// 防止夹角求差出现异常值
auto z_subtract2 = [](const Eigen::VectorXd & a, const Eigen::VectorXd & b) -> Eigen::VectorXd {
Eigen::VectorXd c = a - b; //6 1
c[0] = tools::limit_rad(c[0]);
c[1] = tools::limit_rad(c[1]);
return c;
};
Eigen::VectorXd z2{{B_ypd[0], B_ypd[1], B_ypd[2]}};
ekf_.update(z2, H2, R2, h2, z_subtract2);
// 更新lasttime
lasttime_ = nowtime;
return;
}
Eigen::MatrixXd SmallTarget::h_jacobian() const
{
/// Z(3,1) = H3(3,3) * H2(3,5) * H1(5,5) * H0(5,7) * x(7,1)
// clang-format off
Eigen::MatrixXd H0{
{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0}
};// 5*7
Eigen::VectorXd R_ypd{{ekf_.x[0], ekf_.x[2], ekf_.x[3]}};
Eigen::MatrixXd H_ypd2xyz = tools::ypd2xyz_jacobian(R_ypd); // 3*3
Eigen::MatrixXd H1{
{H_ypd2xyz(0, 0), H_ypd2xyz(0, 1), H_ypd2xyz(0, 2), 0.0, 0.0},
{H_ypd2xyz(1, 0), H_ypd2xyz(1, 1), H_ypd2xyz(1, 2), 0.0, 0.0},
{H_ypd2xyz(2, 0), H_ypd2xyz(2, 1), H_ypd2xyz(2, 2), 0.0, 0.0},
{ 0.0, 0.0, 0.0, 1.0, 0.0},
{ 0.0, 0.0, 0.0, 0.0, 1.0}
};// 5*5
// double pitch = 0;
double yaw = ekf_.x[4];
double roll = ekf_.x[5];
double cos_yaw = cos(yaw);
double sin_yaw = sin(yaw);
double cos_roll = cos(roll);
double sin_roll = sin(roll);
Eigen::MatrixXd H2{
{1.0, 0.0, 0.0, 0.7 * cos_yaw * sin_roll, 0.7 * sin_yaw * cos_roll},
{0.0, 1.0, 0.0, 0.7 * sin_yaw * sin_roll, -0.7 * cos_yaw * cos_roll},
{0.0, 0.0, 1.0, 0.0, -0.7 * sin_roll}
};// 3*5
Eigen::VectorXd B_xyz = point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.7));
Eigen::MatrixXd H3 = tools::xyz2ypd_jacobian(B_xyz);// 3*3
// clang-format on
return H3 * H2 * H1 * H0; // 3*7
// auto h2 = [&](const Eigen::VectorXd & x) -> Eigen::Vector3d {
// Eigen::VectorXd R_ypd{{x[0], x[2], x[3]}};
// Eigen::VectorXd R_xyz = tools::ypd2xyz(R_ypd);
// Eigen::VectorXd R_xyz_and_yr{{R_ypd[0], R_ypd[1], R_ypd[2], x[4], x[5]}};
// Eigen::VectorXd B_xyz = point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.7));
// Eigen::VectorXd B_ypd = tools::xyz2ypd(B_xyz);
// return B_ypd;
// };
}
/// BigTarget
BigTarget::BigTarget() : Target(), spd_fitter_(100, 0.5, 1.884, 2.000) {}
void BigTarget::get_target(
const std::optional<PowerRune> & p, std::chrono::steady_clock::time_point & timestamp)
{
// 如果没有识别,退出函数
static int lost_cn = 0;
if (!p.has_value()) {
unsolvable_ = true;
lost_cn++;
return;
}
static std::chrono::steady_clock::time_point start_timestamp = timestamp;
auto time_gap = tools::delta_time(timestamp, start_timestamp);
// init
if (first_in_) {
unsolvable_ = true;
init(time_gap, p.value());
first_in_ = false;
}
// 处理识别时间间隔过大
if (lost_cn > 6) {
unsolvable_ = true;
tools::logger()->debug("[Target] 丢失buff");
lost_cn = 0;
first_in_ = true;
return;
}
// kalman update
unsolvable_ = false;
update(time_gap, p.value());
// 处理发散
if (
ekf_.x[7] > 1.045 * 1.5 || ekf_.x[7] < 0.78 / 1.5 || ekf_.x[8] > 2.0 * 1.5 ||
ekf_.x[8] < 1.884 / 1.5) {
tools::logger()->debug("[Target] 大符角度发散a: {:.2f}b:{:.2f}", ekf_.x[7], ekf_.x[8]);
first_in_ = true;
return;
}
}
void BigTarget::predict(double dt)
{
// 预测下一个状态
double spd = fit_spd_;
// double spd = ekf_.x[6];
double a = ekf_.x[7];
double w = ekf_.x[8];
double fi = ekf_.x[9];
double t = lasttime_ + dt;
// clang-format off
A_ << 1.0, dt, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,//R_yaw
0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,//v_R_yaw
0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,//R_pitch
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,//R_dis
0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,//yaw
0.0, 0.0, 0.0, 0.0, 0.0, 1.0, voter.clockwise() * dt , 0.0, 0.0, 0.0,//row
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, sin(w * t + fi) - 1, t * a * cos(w * t + fi), a * cos(w * t + fi),//spd
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,//a
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,//w
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0;//theta
// 过程噪声协方差矩阵 //// 调整
auto v1 = 0.9; // 角加速度方差
auto a1 = dt * dt * dt * dt / 4;
auto b1 = dt * dt * dt / 2;
auto c1 = dt * dt;
Q_ << a1 * v1, b1 * v1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
b1 * v1, c1 * v1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.09, 0.0, 0.0, 0.0, 0.0,//row
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0,// spd 0.5 1
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,// a
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,// w
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0;// fi
// 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,// spd 2
// 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
// 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
// 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 4.0;
// 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
// 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
// 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0;
auto f = [&](const Eigen::VectorXd & x) -> Eigen::VectorXd {
Eigen::VectorXd x_prior = x;
x_prior[0] = tools::limit_rad(x_prior[0] + dt * x_prior[1]);
x_prior[2] = tools::limit_rad(x_prior[2]);
x_prior[4] = tools::limit_rad(x_prior[4]); // yaw
x_prior[5] = tools::limit_rad(x_prior[5] + voter.clockwise() *
(-a / w * std::cos(w * t + fi) + a / w * std::cos(w * lasttime_ + fi) + (2.09 - a) * dt)); // roll
x_prior[6] = a * sin(w * t + fi) + 2.09 - a; // spd
return x_prior;
};
// clang-format on
ekf_.predict(A_, Q_, f);
}
void BigTarget::init(double nowtime, const PowerRune & p)
{
// 初始化内部变量
lasttime_ = nowtime;
unsolvable_ = true;
// 初始状态协方差矩阵
x0_.resize(10);
P0_.resize(10, 10);
A_.resize(10, 10);
Q_.resize(10, 10);
H_.resize(7, 10);
R_.resize(7, 7);
// [R_yaw]
// [v_R_yaw]
// [R_pitch]
// [R_dis]
// [yaw]
// [angle/row]
// [spd] 角速度 a*sin(wt) + 2.09 - a
// [a] 0.78-1.045
// [w] 1.884-2.000
// [fi]
// clang-format off
// 初始状态
x0_ << p.ypd_in_world[0], 0.0, p.ypd_in_world[1], p.ypd_in_world[2],
p.ypr_in_world[0], p.ypr_in_world[2],
1.1775, 0.9125, 1.942, 0.0;//std::atan((spd - 2.09) / 0.9125 + 1
// 初始状态协方差矩阵
P0_ << 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 10.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 400.0;
// 状态转移矩阵
// A_
// 过程噪声协方差矩阵 //// 调整
// Q_
// 测量方程矩阵
// H_
// 测量噪声协方差矩阵 //// 调整
// R_
// clang-format on
// 防止夹角求和出现异常值
auto x_add = [](const Eigen::VectorXd & a, const Eigen::VectorXd & b) -> Eigen::VectorXd {
Eigen::VectorXd c = a + b;
c[0] = tools::limit_rad(c[0]);
c[2] = tools::limit_rad(c[2]);
c[4] = tools::limit_rad(c[4]);
c[5] = tools::limit_rad(c[5]);
c[9] = tools::limit_rad(c[9]);
return c;
};
// 创建扩展卡尔曼滤波器对象
ekf_ = tools::ExtendedKalmanFilter(x0_, P0_, x_add);
}
void BigTarget::update(double nowtime, const PowerRune & p)
{
// [R_yaw]
// [v_R_yaw]
// [R_pitch]
// [R_dis]
// [yaw]
// [angle/row] 角度
// [spd] 角速度 a*sin(wt) + 2.09 - a
// [a] 0.78-1.045
// [w] 1.884-2.000
// [fi]
const Eigen::VectorXd & R_ypd = p.ypd_in_world; // R
const Eigen::VectorXd & ypr = p.ypr_in_world;
const Eigen::VectorXd & B_ypd = p.blade_ypd_in_world; // center of blade
// 处理扇叶跳变 angle/row
if (abs(ypr[2] - ekf_.x[5]) > CV_PI / 12) {
for (int i = -5; i <= 5; i++) {
double angle_c = ekf_.x[5] + i * 2 * CV_PI / 5;
if (std::fabs(angle_c - ypr[2]) < CV_PI / 5) {
ekf_.x[5] += i * 2 * CV_PI / 5;
break;
}
}
}
// vote判断是顺时针还是逆时针旋转
voter.vote(ekf_.x[5], ypr[2]);
auto anglelast = ekf_.x[5]; ///
// 预测下一个状态
predict(nowtime - lasttime_);
// [R_yaw] angle0
// [R_pitch] angle1
// [R_dis]
// [angle/row] angle3
// [B_yaw] angle4
// [B_pitch] angle5
// [B_dis]
/// 1.
// [R_yaw] angle0
// [R_pitch] angle1
// [R_dis]
// [angle/row] angle3
// clang-format off
Eigen::MatrixXd H1{
{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, // R_yaw
{0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, // R_pitch
{0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, // R_dis
{0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0} // roll
};
Eigen::MatrixXd R1{
{0.01, 0.0, 0.0, 0.0}, // R_yaw
{0.0, 0.01, 0.0, 0.0}, // R_pitch
{0.0, 0.0, 0.5, 0.0}, // R_dis
{0.0, 0.0, 0.0, 0.1} // roll 1: 0.01 2:0.04
};
// clang-format on
// 防止夹角求差出现异常值
auto z_subtract1 = [](const Eigen::VectorXd & a, const Eigen::VectorXd & b) -> Eigen::VectorXd {
Eigen::VectorXd c = a - b; //4 1
c[0] = tools::limit_rad(c[0]);
c[1] = tools::limit_rad(c[1]);
c[3] = tools::limit_rad(c[3]);
return c;
};
Eigen::VectorXd z1{{R_ypd[0], R_ypd[1], R_ypd[2], ypr[2]}}; // R_ypd roll
ekf_.update(z1, H1, R1, z_subtract1);
///2.
// [B_yaw] angle4
// [B_pitch] angle5
// [B_dis]
// clang-format off
Eigen::MatrixXd H2 = h_jacobian(); // 3*10
Eigen::MatrixXd R2{
{0.01, 0.0, 0.0}, // B_yaw
{0.0, 0.01, 0.0}, // B_pitch
{0.0, 0.0, 0.5} // B_dis
};
// clang-format on
// 定义非线性转换函数h: x -> z
auto h2 = [&](const Eigen::VectorXd & x) -> Eigen::Vector3d {
Eigen::VectorXd R_ypd{{x[0], x[2], x[3]}};
Eigen::VectorXd R_xyz = tools::ypd2xyz(R_ypd);
Eigen::VectorXd R_xyz_and_yr{{R_ypd[0], R_ypd[1], R_ypd[2], x[4], x[5]}};
Eigen::VectorXd B_xyz = point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.7));
Eigen::VectorXd B_ypd = tools::xyz2ypd(B_xyz);
return B_ypd;
};
// 防止夹角求差出现异常值
auto z_subtract2 = [](const Eigen::VectorXd & a, const Eigen::VectorXd & b) -> Eigen::VectorXd {
Eigen::VectorXd c = a - b; //6 1
c[0] = tools::limit_rad(c[0]);
c[1] = tools::limit_rad(c[1]);
return c;
};
Eigen::VectorXd z2{{B_ypd[0], B_ypd[1], B_ypd[2]}};
ekf_.update(z2, H2, R2, h2, z_subtract2);
// 对ekf速度进行最小二乘拟合 ekf_.x[6] -> fitting_speed -> predict position
if (ekf_.x[6] < 2.1 && ekf_.x[6] >= 0) spd_fitter_.add_data(nowtime, ekf_.x[6]);
spd_fitter_.fit();
fit_spd_ = spd_fitter_.sine_function(
nowtime, spd_fitter_.best_result_.A, spd_fitter_.best_result_.omega,
spd_fitter_.best_result_.phi, spd_fitter_.best_result_.C);
spd = voter.clockwise() * (ekf_.x[5] - anglelast) / (nowtime - lasttime_); // 仅供调试
spd = fit_spd_;
if (std::abs(spd) > 4) spd = 0;
// 更新lasttime
lasttime_ = nowtime;
unsolvable_ = false;
return;
}
Eigen::MatrixXd BigTarget::h_jacobian() const
{
/// Z(3,1) = H3(3,3) * H2(3,5) * H1(5,5) * H0(5,10) * x(10,1)
// clang-format off
Eigen::MatrixXd H0{
{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0}
};// 5*7
Eigen::VectorXd R_ypd{{ekf_.x[0], ekf_.x[2], ekf_.x[3]}};
Eigen::MatrixXd H_ypd2xyz = tools::ypd2xyz_jacobian(R_ypd); // 3*3
Eigen::MatrixXd H1{
{H_ypd2xyz(0, 0), H_ypd2xyz(0, 1), H_ypd2xyz(0, 2), 0.0, 0.0},
{H_ypd2xyz(1, 0), H_ypd2xyz(1, 1), H_ypd2xyz(1, 2), 0.0, 0.0},
{H_ypd2xyz(2, 0), H_ypd2xyz(2, 1), H_ypd2xyz(2, 2), 0.0, 0.0},
{ 0.0, 0.0, 0.0, 1.0, 0.0},
{ 0.0, 0.0, 0.0, 0.0, 1.0}
};// 5*5
// double pitch = 0;
double yaw = ekf_.x[4];
double roll = ekf_.x[5];
double cos_yaw = cos(yaw);
double sin_yaw = sin(yaw);
double cos_roll = cos(roll);
double sin_roll = sin(roll);
Eigen::MatrixXd H2{
{1.0, 0.0, 0.0, 0.7 * cos_yaw * sin_roll, 0.7 * sin_yaw * cos_roll},
{0.0, 1.0, 0.0, 0.7 * sin_yaw * sin_roll, -0.7 * cos_yaw * cos_roll},
{0.0, 0.0, 1.0, 0.0, -0.7 * sin_roll}
};// 3*5
Eigen::VectorXd B_xyz = point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.7));
Eigen::MatrixXd H3 = tools::xyz2ypd_jacobian(B_xyz);// 3*3
// clang-format on
return H3 * H2 * H1 * H0; // 3*7
// auto h2 = [&](const Eigen::VectorXd & x) -> Eigen::Vector3d {
// Eigen::VectorXd R_ypd{{x[0], x[2], x[3]}};
// Eigen::VectorXd R_xyz = tools::ypd2xyz(R_ypd);
// Eigen::VectorXd R_xyz_and_yr{{R_ypd[0], R_ypd[1], R_ypd[2], x[4], x[5]}};
// Eigen::VectorXd B_xyz = point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.7));
// Eigen::VectorXd B_ypd = tools::xyz2ypd(B_xyz);
// return B_ypd;
// };
}
} // namespace auto_buff