179 lines
5.4 KiB
C++
179 lines
5.4 KiB
C++
#include <fmt/core.h>
|
|
|
|
#include <chrono>
|
|
#include <fstream>
|
|
#include <nlohmann/json.hpp>
|
|
#include <opencv2/opencv.hpp>
|
|
|
|
#include "tasks/auto_buff/buff_aimer.hpp"
|
|
#include "tasks/auto_buff/buff_detector.hpp"
|
|
#include "tasks/auto_buff/buff_solver.hpp"
|
|
#include "tasks/auto_buff/buff_target.hpp"
|
|
#include "tasks/auto_buff/buff_type.hpp"
|
|
#include "tools/exiter.hpp"
|
|
#include "tools/img_tools.hpp"
|
|
#include "tools/logger.hpp"
|
|
#include "tools/math_tools.hpp"
|
|
#include "tools/plotter.hpp"
|
|
|
|
const std::string keys =
|
|
"{help h usage ? | | 输出命令行参数说明 }"
|
|
"{config-path c | configs/sentry.yaml | yaml配置文件的路径}"
|
|
"{start-index s | 0 | 视频起始帧下标 }"
|
|
"{end-index e | 0 | 视频结束帧下标 }"
|
|
"{@input-path | | avi和txt文件的路径}";
|
|
|
|
int main(int argc, char * argv[])
|
|
{
|
|
// 读取命令行参数
|
|
cv::CommandLineParser cli(argc, argv, keys);
|
|
if (cli.has("help")) {
|
|
cli.printMessage();
|
|
return 0;
|
|
}
|
|
auto input_path = cli.get<std::string>(0);
|
|
auto config_path = cli.get<std::string>("config-path");
|
|
auto start_index = cli.get<int>("start-index");
|
|
auto end_index = cli.get<int>("end-index");
|
|
|
|
tools::Plotter plotter;
|
|
tools::Exiter exiter;
|
|
|
|
auto video_path = fmt::format("{}.avi", input_path);
|
|
auto text_path = fmt::format("{}.txt", input_path);
|
|
cv::VideoCapture video(video_path);
|
|
std::ifstream text(text_path);
|
|
|
|
auto_buff::Buff_Detector detector(config_path);
|
|
auto_buff::Solver solver(config_path);
|
|
// auto_buff::SmallTarget target;
|
|
auto_buff::BigTarget target;
|
|
auto_buff::Aimer aimer(config_path);
|
|
|
|
cv::Mat img, drawing;
|
|
auto t0 = std::chrono::steady_clock::now();
|
|
|
|
io::Command last_command;
|
|
double last_t = -1;
|
|
|
|
video.set(cv::CAP_PROP_POS_FRAMES, start_index);
|
|
for (int i = 0; i < start_index; i++) {
|
|
double t, w, x, y, z;
|
|
text >> t >> w >> x >> y >> z;
|
|
}
|
|
|
|
for (int frame_count = start_index; !exiter.exit(); frame_count++) {
|
|
if (end_index > 0 && frame_count > end_index) break;
|
|
|
|
video.read(img);
|
|
if (img.empty()) break;
|
|
|
|
double t, w, x, y, z;
|
|
text >> t >> w >> x >> y >> z;
|
|
auto timestamp = t0 + std::chrono::microseconds(int(t * 1e6));
|
|
|
|
/// 自瞄核心逻辑
|
|
|
|
solver.set_R_gimbal2world({w, x, y, z});
|
|
|
|
auto power_runes = detector.detect(img);
|
|
|
|
solver.solve(power_runes);
|
|
|
|
target.get_target(power_runes, timestamp);
|
|
|
|
auto target_copy = target;
|
|
|
|
auto command = aimer.aim(target_copy, timestamp, 22, false);
|
|
|
|
// cboard.send(command);
|
|
|
|
// -------------- 调试输出 --------------
|
|
|
|
nlohmann::json data;
|
|
|
|
// data["bullet_speed"] = cboard.bullet_speed;
|
|
|
|
// buff原始观测数据
|
|
if (power_runes.has_value()) {
|
|
const auto & p = power_runes.value();
|
|
data["buff_R_yaw"] = p.ypd_in_world[0];
|
|
data["buff_R_pitch"] = p.ypd_in_world[1];
|
|
data["buff_R_dis"] = p.ypd_in_world[2];
|
|
data["buff_yaw"] = p.ypr_in_world[0] * 57.3;
|
|
data["buff_pitch"] = p.ypr_in_world[1] * 57.3;
|
|
data["buff_roll"] = p.ypr_in_world[2] * 57.3;
|
|
}
|
|
|
|
if (!target.is_unsolve()) {
|
|
auto & p = power_runes.value();
|
|
|
|
// 显示
|
|
for (int i = 0; i < 4; i++) tools::draw_point(img, p.target().points[i]);
|
|
tools::draw_point(img, p.target().center, {0, 0, 255}, 3);
|
|
tools::draw_point(img, p.r_center, {0, 0, 255}, 3);
|
|
|
|
// 当前帧target更新后buff
|
|
auto Rxyz_in_world_now = target.point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.0));
|
|
auto image_points =
|
|
solver.reproject_buff(Rxyz_in_world_now, target.ekf_x()[4], target.ekf_x()[5]);
|
|
tools::draw_points(
|
|
img, std::vector<cv::Point2f>(image_points.begin(), image_points.begin() + 4), {0, 255, 0});
|
|
tools::draw_points(
|
|
img, std::vector<cv::Point2f>(image_points.begin() + 4, image_points.end()), {0, 255, 0});
|
|
|
|
// buff瞄准位置(预测)
|
|
double dangle = target.ekf_x()[5] - target_copy.ekf_x()[5];
|
|
auto Rxyz_in_world_pre = target.point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.0));
|
|
image_points =
|
|
solver.reproject_buff(Rxyz_in_world_pre, target_copy.ekf_x()[4], target_copy.ekf_x()[5]);
|
|
tools::draw_points(
|
|
img, std::vector<cv::Point2f>(image_points.begin(), image_points.begin() + 4), {255, 0, 0});
|
|
tools::draw_points(
|
|
img, std::vector<cv::Point2f>(image_points.begin() + 4, image_points.end()), {255, 0, 0});
|
|
|
|
// 观测器内部数据
|
|
Eigen::VectorXd x = target.ekf_x();
|
|
data["R_yaw"] = x[0];
|
|
data["R_V_yaw"] = x[1];
|
|
data["R_pitch"] = x[2];
|
|
data["R_dis"] = x[3];
|
|
data["yaw"] = x[4] * 57.3;
|
|
|
|
data["angle"] = x[5] * 57.3;
|
|
data["spd"] = x[6] * 57.3;
|
|
if (x.size() >= 10) {
|
|
data["spd"] = x[6];
|
|
data["a"] = x[7];
|
|
data["w"] = x[8];
|
|
data["fi"] = x[9];
|
|
data["spd0"] = target.spd;
|
|
}
|
|
}
|
|
|
|
// 云台响应情况
|
|
Eigen::Vector3d ypr = tools::eulers(solver.R_gimbal2world(), 2, 1, 0);
|
|
data["gimbal_yaw"] = ypr[0] * 57.3;
|
|
data["gimbal_pitch"] = -ypr[1] * 57.3;
|
|
|
|
if (command.control) {
|
|
data["cmd_yaw"] = command.yaw * 57.3;
|
|
data["cmd_pitch"] = command.pitch * 57.3;
|
|
}
|
|
|
|
plotter.plot(data);
|
|
|
|
cv::imshow("result", img);
|
|
|
|
int key = cv::waitKey(1);
|
|
if (key == 'q') break;
|
|
while (key == ' ') {
|
|
int y = cv::waitKey(30);
|
|
if (y == 'q') break;
|
|
}
|
|
}
|
|
cv::destroyAllWindows();
|
|
text.close(); // 关闭文件
|
|
|
|
return 0;
|
|
} |