#include "decider.hpp" #include #include #include #include "tools/logger.hpp" #include "tools/math_tools.hpp" namespace omniperception { Decider::Decider(const std::string & config_path) : detector_(config_path), count_(0) { auto yaml = YAML::LoadFile(config_path); img_width_ = yaml["image_width"].as(); img_height_ = yaml["image_height"].as(); fov_h_ = yaml["fov_h"].as(); fov_v_ = yaml["fov_v"].as(); new_fov_h_ = yaml["new_fov_h"].as(); new_fov_v_ = yaml["new_fov_v"].as(); enemy_color_ = (yaml["enemy_color"].as() == "red") ? auto_aim::Color::red : auto_aim::Color::blue; mode_ = yaml["mode"].as(); } io::Command Decider::decide( auto_aim::YOLO & yolo, const Eigen::Vector3d & gimbal_pos, io::USBCamera & usbcam1, io::USBCamera & usbcam2, io::Camera & back_camera) { Eigen::Vector2d delta_angle; io::USBCamera * cams[] = {&usbcam1, &usbcam2}; cv::Mat usb_img; std::chrono::steady_clock::time_point timestamp; if (count_ < 0 || count_ > 2) { throw std::runtime_error("count_ out of valid range [0,2]"); } if (count_ == 2) { back_camera.read(usb_img, timestamp); } else { cams[count_]->read(usb_img, timestamp); } auto armors = yolo.detect(usb_img); auto empty = armor_filter(armors); if (!empty) { if (count_ == 2) { delta_angle = this->delta_angle(armors, "back"); } else { delta_angle = this->delta_angle(armors, cams[count_]->device_name); } tools::logger()->debug( "[{} camera] delta yaw:{:.2f},target pitch:{:.2f},armor number:{},armor name:{}", (count_ == 2 ? "back" : cams[count_]->device_name), delta_angle[0], delta_angle[1], armors.size(), auto_aim::ARMOR_NAMES[armors.front().name]); count_ = (count_ + 1) % 3; return io::Command{ true, false, tools::limit_rad(gimbal_pos[0] + delta_angle[0] / 57.3), tools::limit_rad(delta_angle[1] / 57.3)}; } count_ = (count_ + 1) % 3; // 如果没有找到目标,返回默认命令 return io::Command{false, false, 0, 0}; } io::Command Decider::decide( auto_aim::YOLO & yolo, const Eigen::Vector3d & gimbal_pos, io::Camera & back_cammera) { cv::Mat img; std::chrono::steady_clock::time_point timestamp; back_cammera.read(img, timestamp); auto armors = yolo.detect(img); auto empty = armor_filter(armors); if (!empty) { auto delta_angle = this->delta_angle(armors, "back"); tools::logger()->debug( "[back camera] delta yaw:{:.2f},target pitch:{:.2f},armor number:{},armor name:{}", delta_angle[0], delta_angle[1], armors.size(), auto_aim::ARMOR_NAMES[armors.front().name]); return io::Command{ true, false, tools::limit_rad(gimbal_pos[0] + delta_angle[0] / 57.3), tools::limit_rad(delta_angle[1] / 57.3)}; } return io::Command{false, false, 0, 0}; } io::Command Decider::decide(const std::vector & detection_queue) { if (detection_queue.empty()) { return io::Command{false, false, 0, 0}; } DetectionResult dr = detection_queue.front(); if (dr.armors.empty()) return io::Command{false, false, 0, 0}; tools::logger()->info( "omniperceptron find {},delta yaw is {:.4f}", auto_aim::ARMOR_NAMES[dr.armors.front().name], dr.delta_yaw * 57.3); return io::Command{true, false, dr.delta_yaw, dr.delta_pitch}; }; Eigen::Vector2d Decider::delta_angle( const std::list & armors, const std::string & camera) { Eigen::Vector2d delta_angle; if (camera == "left") { delta_angle[0] = 62 + (new_fov_h_ / 2) - armors.front().center_norm.x * new_fov_h_; delta_angle[1] = armors.front().center_norm.y * new_fov_v_ - new_fov_v_ / 2; return delta_angle; } else if (camera == "right") { delta_angle[0] = -62 + (new_fov_h_ / 2) - armors.front().center_norm.x * new_fov_h_; delta_angle[1] = armors.front().center_norm.y * new_fov_v_ - new_fov_v_ / 2; return delta_angle; } else { delta_angle[0] = 170 + (54.2 / 2) - armors.front().center_norm.x * 54.2; delta_angle[1] = armors.front().center_norm.y * 44.5 - 44.5 / 2; return delta_angle; } } bool Decider::armor_filter(std::list & armors) { if (armors.empty()) return true; // 过滤非敌方装甲板 armors.remove_if([&](const auto_aim::Armor & a) { return a.color != enemy_color_; }); // 25赛季没有5号装甲板 armors.remove_if([&](const auto_aim::Armor & a) { return a.name == auto_aim::ArmorName::five; }); // 不打工程 // armors.remove_if([&](const auto_aim::Armor & a) { return a.name == auto_aim::ArmorName::two; }); // 不打前哨站 armors.remove_if( [&](const auto_aim::Armor & a) { return a.name == auto_aim::ArmorName::outpost; }); // 过滤掉刚复活无敌的装甲板 armors.remove_if([&](const auto_aim::Armor & a) { return std::find(invincible_armor_.begin(), invincible_armor_.end(), a.name) != invincible_armor_.end(); }); return armors.empty(); } void Decider::set_priority(std::list & armors) { if (armors.empty()) return; const PriorityMap & priority_map = (mode_ == MODE_ONE) ? mode1 : mode2; if (!armors.empty()) { for (auto & armor : armors) { armor.priority = priority_map.at(armor.name); } } } void Decider::sort(std::vector & detection_queue) { if (detection_queue.empty()) return; // 对每个 DetectionResult 调用 armor_filter 和 set_priority for (auto & dr : detection_queue) { armor_filter(dr.armors); set_priority(dr.armors); // 对每个 DetectionResult 中的 armors 进行排序 dr.armors.sort( [](const auto_aim::Armor & a, const auto_aim::Armor & b) { return a.priority < b.priority; }); } // 根据优先级对 DetectionResult 进行排序 std::sort( detection_queue.begin(), detection_queue.end(), [](const DetectionResult & a, const DetectionResult & b) { return a.armors.front().priority < b.armors.front().priority; }); } Eigen::Vector4d Decider::get_target_info( const std::list & armors, const std::list & targets) { if (armors.empty() || targets.empty()) return Eigen::Vector4d::Zero(); auto target = targets.front(); for (const auto & armor : armors) { if (armor.name == target.name) { return Eigen::Vector4d{ armor.xyz_in_gimbal[0], armor.xyz_in_gimbal[1], 1, static_cast(armor.name) + 1}; //避免歧义+1(详见通信协议) } } return Eigen::Vector4d::Zero(); } void Decider::get_invincible_armor(const std::vector & invincible_enemy_ids) { invincible_armor_.clear(); if (invincible_enemy_ids.empty()) return; for (const auto & id : invincible_enemy_ids) { tools::logger()->info("invincible armor id: {}", id); invincible_armor_.push_back(auto_aim::ArmorName(id - 1)); } } void Decider::get_auto_aim_target( std::list & armors, const std::vector & auto_aim_target) { if (auto_aim_target.empty()) return; std::vector auto_aim_targets; for (const auto & target : auto_aim_target) { if (target <= 0 || static_cast(target) > auto_aim::ARMOR_NAMES.size()) { tools::logger()->warn("Received invalid auto_aim target value: {}", int(target)); continue; } auto_aim_targets.push_back(static_cast(target - 1)); tools::logger()->info("nav send auto_aim target is {}", auto_aim::ARMOR_NAMES[target - 1]); } if (auto_aim_targets.empty()) return; armors.remove_if([&](const auto_aim::Armor & a) { return std::find(auto_aim_targets.begin(), auto_aim_targets.end(), a.name) == auto_aim_targets.end(); }); } } // namespace omniperception