std::isnan用法

时间: 2025-07-08 20:16:40 浏览: 15
<think>好的,用户现在问的是`std::isnan`的用法。之前他问过关于`LoggerManager::getLogger`方法的实现,涉及C++的多线程、智能指针和设计模式。现在转向数值处理,可能是在开发过程中遇到了需要处理浮点数异常的情况,比如日志系统中记录数值时检测无效数据。 首先,我需要确认用户对`std::isnan`的了解程度。他可能知道这是一个检测NaN的函数,但具体用法和注意事项可能不太清楚。需要解释清楚函数的作用、参数类型、返回值以及在不同标准中的区别。 用户可能是在调试时遇到了NaN的问题,或者需要在代码中处理浮点数的异常情况。比如在数据处理、科学计算或日志记录时,确保数值有效。需要强调`std::isnan`与其他检查函数(如`std::isinf`)的区别,以及为什么不能直接用比较操作符来判断NaN。 另外,用户可能对C++11和C++03的差异不太熟悉,需要指出`std::isnan`在C++11中的改进,比如对整型的处理会导致编译错误,避免误用。同时,提醒他在不同编译器或标准下的行为可能不同,特别是在旧代码中可能存在用`isnan`宏的情况,需要注意包含正确的头文件(如<cmath>)和使用命名空间。 还要考虑到用户的应用场景,比如在日志系统中,可能需要在记录前检查数值的有效性,避免将NaN写入日志导致后续处理错误。这时候正确使用`std::isnan`可以提前捕获问题,保证系统健壮性。 最后,提供示例代码帮助用户理解具体用法,包括浮点数和双精度的情况,并指出常见错误,比如用`x == NAN`这种方式无效,强调使用标准库函数的重要性。这样用户能够快速应用到实际项目中,避免常见的陷阱。</think>`std::isnan` 是 C++ 标准库中用于检测浮点数是否为 **NaN(Not-a-Number)** 的模板函数,以下是详细解析: --- ### **基本功能** - **作用**:判断浮点数是否是 NaN(无效数值) - **头文件**:`#include <cmath>` - **返回值**:`bool` 类型,若参数是 NaN 则返回 `true`,否则返回 `false` --- ### **用法示例** ```cpp #include <cmath> #include <iostream> int main() { double x = 0.0 / 0.0; // 生成 NaN double y = 1.0; if (std::isnan(x)) { std::cout << "x 是 NaN" << std::endl; // 输出此行 } if (!std::isnan(y)) { std::cout << "y 是有效数值" << std::endl; // 输出此行 } } ``` --- ### **关键特性** 1. **参数类型支持** - 支持 `float`, `double`, `long double` 及兼容类型 - **C++11 起**:若传递整型参数会编译报错(如 `std::isnan(5)` 非法) 2. **与普通比较的区别** **错误方式**: ```cpp double x = NaN; if (x == NaN) { /* 永远不会触发 */ } ``` - 因 NaN 不等于任何值(包括自身),必须用 `std::isnan` 判断 3. **与其他检测函数对比** - `std::isinf(x)`: 检测是否无穷大(正负无穷) - `std::isfinite(x)`: 检测是否是有限数值(非 NaN 且非无穷) --- ### **适用场景** - 科学计算中处理无效运算结果(如 `sqrt(-1)`) - 数据清洗时过滤异常值 - 调试时验证浮点数的合法性 --- ### **注意事项** 1. **C++11 前行为差异** - C++03 中 `std::isnan` 可能通过宏实现,对整型参数可能返回 `false` 而非报错 2. **编译器兼容性** - 确保启用 C++11 或更高标准(如编译选项 `-std=c++11`) 3. **NaN 生成方式** - 常见来源:`0.0/0.0`, `sqrt(-1)`, `log(-1)` 等非法运算 --- ### **扩展:C 风格函数** C 语言中对应 `isnan()` 宏(需包含 `<math.h>`),但行为可能因实现不同。C++ 推荐优先使用 `std::isnan`。
阅读全文

相关推荐

OpenSim::Logger::setLevel(OpenSim::Logger::Level::Error); OpenSim::Model model("C:/IKsolver/Model_Pose2Sim_Halpe26_scaled.osim"); SimTK::State& state = model.initSystem(); model.realizePosition(state); vector<string> labels{ "Hip", "RHip", "RKnee", "RAnkle", "RBigToe", "RSmallToe", "RHeel", "LHip", "LKnee", "LAnkle", "LBigToe", "LSmallToe", "LHeel", "Neck", "Head", "Nose", "RShoulder", "RElbow", "RWrist", "LShoulder", "LElbow", "LWrist"}; vector<double> order = {2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 0.2, 0.0, 0.0, 2, 1, 1, 2, 1, 1}; Set<MarkerWeight> markerWeights; size_t nc = labels.size(); size_t nr = 1; for (size_t m{0}; m < nc; ++m) markerWeights.adoptAndAppend( new MarkerWeight(labels[m], double(order[m]))); SimTK::Array_<CoordinateReference> coordRefs; auto t0 = std::chrono::steady_clock::now(); TimeSeriesTable_<SimTK::Vec3> markerData; markerData.setColumnLabels(labels); SimTK::RowVector_<SimTK::Vec3> row(nc); for (size_t i = 0; i < 22; ++i) { row[i] = SimTK::Vec3(data[3*i], data[3*i+1], data[3*i+2]); } markerData.appendRow(0, row); MarkersReference markersRef(markerData, markerWeights); for (const auto& label : labels) { std::cout << label << ": " << markerWeights.get(label).getWeight() << std::endl; } for (int i = 0; i < model.getMarkerSet().getSize(); ++i) { std::cout << model.getMarkerSet()[i].getName() << std::endl; } OpenSim::InverseKinematicsSolver iksolver(model, markersRef, coordRefs, SimTK::Infinity); iksolver.setAccuracy(1.0e-9); try { iksolver.assemble(state); iksolver.track(state); } catch (const std::exception& e) { std::cerr << "IK solve failed: " << e.what() << std::endl; } model.realizePosition(state); CoordinateSet coordSet = model.getCoordinateSet(); try { model.realizePosition(state); auto val = coordSet[0].getValue(state); std::cout << "val: " << val << std::endl; } catch (const std::exception& e) { std::cerr << "Caught exception at getValue(): " << e.what() << std::endl; } auto t1 = std::chrono::steady_clock::now(); std::cout << "Elapsed: " << std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0).count() << " ms" << std::endl; SimTK::Array_<double> markerErrors; iksolver.computeCurrentMarkerErrors(markerErrors); double totalError = 0.0; for (size_t i = 0; i < markerErrors.size(); ++i) { double e = markerErrors[i]; totalError += e; std::cout << labels[i] << " error: " << e << " m" << std::endl; } std::cout << "Total marker error sum: " << totalError << " m" << std::endl; for (int i = 0; i < coordSet.getSize(); ++i){ std::cout << coordSet[i].getName() << ": " << coordSet[i].getValue(state) << std::endl; auto val = coordSet[i].getValue(state); if (std::isnan(val)) { std::cout << coordSet[i].getName() << ": NaN " << std::endl; } else { std::cout << coordSet[i].getName() << ": " << val << std::endl; } } cout << coordSet[0].getValue(state) << endl; IK沒辦法輸出為什麼 Hip: 2 RHip: 2 RKnee: 2 RAnkle: 1 RBigToe: 1 RSmallToe: 1 RHeel: 1 LHip: 2 LKnee: 1 LAnkle: 1 LBigToe: 1 LSmallToe: 1 LHeel: 1 Neck: 0.2 Head: 0 Nose: 0 RShoulder: 2 RElbow: 1 RWrist: 1 LShoulder: 2 LElbow: 1 LWrist: 1 Nose Head Neck LShoulder RShoulder LElbow RElbow LWrist RWrist Hip LHip RHip LKnee RKnee LAnkle RAnkle LBigToe LSmallToe LHeel RBigToe RSmallToe RHeel PS C:\IKsolver\build>

#include <iostream> #include <vector> #include <string> #include <cstring> #include <cmath> #include <algorithm> #include <onnxruntime_cxx_api.h> // 检查浮点数有效性 bool is_valid_float(float value) { return !std::isnan(value) && std::isfinite(value); } int main() { try { // 1. 初始化ONNX Runtime环境 //Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "ONNX-Runtime"); Ort::Env env(ORT_LOGGING_LEVEL_VERBOSE, "ONNX-Runtime"); Ort::SessionOptions session_options; // 2. 加载ONNX模型 Ort::Session session(env, L"model.onnx", session_options); Ort::AllocatorWithDefaultOptions allocator; #if 0 auto model_metadata = session.GetModelMetadata(); auto pModelProducer = model_metadata.GetProducerNameAllocated(allocator); std::cout << "Model producer: " << pModelProducer.get() << "\n"; // 获取所有权重名称 size_t num_nodes = session.GetOverridableInitializerCount(); for (size_t i = 0; i < num_nodes; i++) { auto name_ptr = session.GetOverridableInitializerNameAllocated(i, allocator); std::cout << "Override name: " << *name_ptr << "\n"; } #endif // 3. 获取模型输入信息 size_t num_inputs = session.GetInputCount(); std::vector<std::string> input_names; std::vector<std::vector<int64_t>> input_shapes; std::vector<ONNXTensorElementDataType> input_types; std::cout << "===== Model Input Analysis =====\n"; for (size_t i = 0; i < num_inputs; i++) { auto name_ptr = session.GetInputNameAllocated(i, allocator); input_names.push_back(name_ptr.get()); auto type_info = session.GetInputTypeInfo(i); auto tensor_info = type_info.GetTensorTypeAndShapeInfo(); input_shapes.push_back(tensor_info.GetShape()); input_types.push_back(tensor_info.GetElementType()); std::cout << "Input [" << i << "]: " << input_names.back() << " | Type: " << input_types.back() << " | Shape: ["; for (auto dim : input_shapes.back()) { std::cout << dim << (dim == -1 ? "(dynamic)" : "") << ", "; } std::cout << "]\n"; } // 4. 获取模型输出信息 size_t num_outputs = session.GetOutputCount(); std::vector<std::string> output_names; std::vector<std::vector<int64_t>> output_shapes; std::cout << "\n===== Model Output Analysis =====\n"; for (size_t i = 0; i < num_outputs; i++) { auto name_ptr = session.GetOutputNameAllocated(i, allocator); output_names.push_back(name_ptr.get()); auto type_info = session.GetOutputTypeInfo(i); auto tensor_info = type_info.GetTensorTypeAndShapeInfo(); output_shapes.push_back(tensor_info.GetShape()); std::cout << "Output [" << i << "]: " << output_names.back() << " | Type: " << tensor_info.GetElementType() << " | Shape: ["; for (auto dim : output_shapes.back()) { std::cout << dim << (dim == -1 ? "(dynamic)" : "") << ", "; } std::cout << "]\n"; } // 5. 准备输入数据 //std::vector<int64_t> token_ids = { 35377 }; std::vector<int64_t> token_ids = { 100 }; //std::vector<int64_t> token_ids = { 70645 }; const size_t seq_length = token_ids.size(); const int64_t batch_size = 1; // 6. 动态调整输入形状 for (auto& shape : input_shapes) { for (size_t i = 0; i < shape.size(); i++) { if (shape[i] == -1) { if (i == 0) shape[i] = batch_size; // 第一维 = batch size else if (i == 1) shape[i] = seq_length; // 第二维 = 序列长度 else shape[i] = 1; // 其他维度设为1 } } } // 7. 创建输入张量 std::vector<Ort::Value> input_tensors; Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeDefault); std::cout << "\n===== Input Tensor Preparation =====\n"; for (size_t i = 0; i < num_inputs; i++) { const auto& name = input_names[i]; const auto& shape = input_shapes[i]; // 计算预期元素数量 size_t expected_elements = 1; for (auto dim : shape) expected_elements *= dim; std::cout << "Preparing input: " << name << " | Shape: ["; for (auto dim : shape) std::cout << dim << ", "; std::cout << "] | Elements: " << expected_elements << "\n"; if (name.find("input") != std::string::npos || name.find("ids") != std::string::npos) { if (shape.size() >= 2 && shape[0] == batch_size && shape[1] == seq_length) { input_tensors.emplace_back(Ort::Value::CreateTensor<int64_t>( memory_info, token_ids.data(), token_ids.size(), shape.data(), shape.size() )); std::cout << " Using token_ids data (size: " << token_ids.size() << ")\n"; } else { throw std::runtime_error("Input shape mismatch for token_ids"); } } else if (name.find("mask") != std::string::npos) { std::vector<int64_t> mask(seq_length, 1); input_tensors.emplace_back(Ort::Value::CreateTensor<int64_t>( memory_info, mask.data(), mask.size(), shape.data(), shape.size() )); std::cout << " Using attention_mask data\n"; } else if (name.find("type") != std::string::npos) { std::vector<int64_t> type_ids(seq_length, 0); input_tensors.emplace_back(Ort::Value::CreateTensor<int64_t>( memory_info, type_ids.data(), type_ids.size(), shape.data(), shape.size() )); std::cout << " Using token_type_ids data\n"; } else { throw std::runtime_error("Unsupported input type: " + name); } } // 8. 准备输入/输出名称指针 std::vector<const char*> input_names_ptr; for (const auto& name : input_names) input_names_ptr.push_back(name.c_str()); std::vector<const char*> output_names_ptr; for (const auto& name : output_names) output_names_ptr.push_back(name.c_str()); // 9. 运行模型推理 std::cout << "\n===== Running Inference =====\n"; auto output_tensors = session.Run( Ort::RunOptions{ nullptr }, input_names_ptr.data(), input_tensors.data(), input_tensors.size(), output_names_ptr.data(), output_names_ptr.size() ); // 10. 分析输出结果 std::cout << "\n===== Inference Results =====\n"; for (size_t i = 0; i < output_tensors.size(); i++) { auto& tensor = output_tensors[i]; if (!tensor.IsTensor()) { std::cerr << " Output [" << i << "] is not a tensor\n"; continue; } auto tensor_info = tensor.GetTensorTypeAndShapeInfo(); auto shape = tensor_info.GetShape(); size_t element_count = tensor_info.GetElementCount(); auto data_type = tensor_info.GetElementType(); std::cout << "Output [" << i << "]: " << output_names[i] << "\n"; std::cout << " Shape: ["; for (auto dim : shape) std::cout << dim << ", "; std::cout << "] | Elements: " << element_count << "\n"; // 关键诊断:检查输出维度 if (shape.size() >= 2 && shape[1] != seq_length) { std::cout << "WARNING: Output sequence length (" << shape[1] << ") does not match input length (" << seq_length << ")\n"; } // 详细输出分析 if (data_type == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT) { double* data1 = tensor.GetTensorMutableData<double>(); float* data = tensor.GetTensorMutableData<float>(); // 统计有效值 int valid_count = 0; int nan_count = 0; float min_val = FLT_MAX, max_val = -FLT_MAX; for (size_t j = 0; j < element_count; j++) { if (is_valid_float(data[j])) { valid_count++; if (data[j] < min_val) min_val = data[j]; if (data[j] > max_val) max_val = data[j]; } else { nan_count++; } } std::cout << " Valid values: " << valid_count << "/" << element_count << "\n"; if (valid_count > 0) { std::cout << " Value range: [" << min_val << ", " << max_val << "]\n"; // 打印完整输出(元素少时) if (element_count <= 20) { std::cout << " Full output: "; for (size_t j = 0; j < element_count; j++) { std::cout << data[j] << " "; } std::cout << "\n"; } } } else { std::cout << " Data type: " << data_type << " (printing not supported)\n"; } std::cout << "\n"; } } catch (const Ort::Exception& e) { std::cerr << "ONNX Runtime Error: " << e.what() << "\n"; return 1; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << "\n"; return 1; } std::cout << "Inference completed. Press Enter to exit..."; getchar(); return 0; }这代码输入没问题,但是输出的向量是无效的float值

#include <opencv2/opencv.hpp> #include <iostream> #include <fstream> #include <vector>   // 生成PLY点云文件(二进制格式,兼容CloudCompare) void savePointCloudToPLY(const cv::Mat & points, const cv::Mat & colors, const std::string & filename, double min_depth = 0.1, double max_depth = 10000.0) { std::ofstream plyFile(filename, std::ios::binary); if (!plyFile.is_open()) { std::cerr << "Error: Could not open PLY file for writing." << std::endl; return; }   // 统计有效点数量 int validCount = 0; for (int y = 0; y < points.rows; y++) { for (int x = 0; x < points.cols; x++) { cv::Vec3f point = points.at<cv::Vec3f>(y, x); // 检查深度值是否在有效范围内且不是无穷大 if (point[2] > min_depth && point[2] < max_depth && !std::isinf(point[0]) && !std::isinf(point[1]) && !std::isinf(point[2])) { validCount++; } } }   // 写入PLY头(二进制格式) plyFile << "ply\n"; plyFile << "format binary_little_endian 1.0\n"; plyFile << "element vertex " << validCount << "\n"; plyFile << "property float x\n"; plyFile << "property float y\n"; plyFile << "property float z\n"; plyFile << "property uchar red\n"; plyFile << "property uchar green\n"; plyFile << "property uchar blue\n"; plyFile << "end_header\n";   // 写入点云数据(二进制) for (int y = 0; y < points.rows; y++) { for (int x = 0; x < points.cols; x++) { cv::Vec3f point = points.at<cv::Vec3f>(y, x); cv::Vec3b color = colors.at<cv::Vec3b>(y, x);   // 过滤无效点 if (point[2] > min_depth && point[2] < max_depth && !std::isinf(point[0]) && !std::isinf(point[1]) && !std::isinf(point[2])) { // 写入坐标(小端序浮点数) plyFile.write(reinterpret_cast<const char*>(&point[0]), sizeof(float)); plyFile.write(reinterpret_cast<const char*>(&point[1]), sizeof(float)); plyFile.write(reinterpret_cast<const char*>(&point[2]), sizeof(float));   // 写入颜色(注意OpenCV使用BGR顺序) plyFile.write(reinterpret_cast<const char*>(&color[2]), sizeof(uint8_t)); // R plyFile.write(reinterpret_cast<const char*>(&color[1]), sizeof(uint8_t)); // G plyFile.write(reinterpret_cast<const char*>(&color[0]), sizeof(uint8_t)); // B } } }   plyFile.close(); std::cout << "Saved " << validCount << " points to " << filename << std::endl; }   int main() { // 1. 定义投影矩阵(使用您提供的数据) cv::Mat P1 = (cv::Mat_<double>(3, 4) << 2791.1531638651541, -3164.2425130586262, -1932.4112841478736, 9203066124.8177795410156, -3171.4539351046769, -2823.8486979863924, -2106.1412396703704, 11236470204.1201114654541, -0.0094942232932, -0.0067457239026, -0.9999321751664, 28815.1627210603910);   cv::Mat P2 = (cv::Mat_<double>(3, 4) << 2791.1885344521997, -3164.2173819650006, -1928.6860517671789, 9202236641.5202198028564, -3171.4539351046769, -2823.8486979863924, -2106.1412396703704, 11236470204.1201095581055, -0.0094942232932, -0.0067457239026, -0.9999321751664, 28815.1627210603947);   // 2. 读取视差图和左影像(用于点云着色) cv::Mat disparity = cv::imread("C:\\Users\\lzr15\\Desktop\\data1\\data1\\DispImg\\017ER030_017ER031_DISP_ET0.tif", cv::IMREAD_UNCHANGED); // 16位视差图 cv::Mat leftImage = cv::imread("C:\\Users\\lzr15\\Desktop\\data1\\data1\\EpiImg\\017ER030_017ER031_ET0\\017ER030_REC.tif"); // 左核线影像   if (disparity.empty() || leftImage.empty()) { std::cerr << "Error: Could not read input images." << std::endl; return -1; }   // 3. 验证视差图数据 std::cout << "Disparity image size: " << disparity.size() << std::endl; std::cout << "Disparity image type: " << disparity.type() << " (CV_16UC1=" << CV_16UC1 << ")" << std::endl;   // 检查视差图是否为16位格式 if (disparity.type() != CV_16UC1 && disparity.type() != CV_16SC1) { std::cerr << "Warning: Disparity image is not 16-bit format. Results may be incorrect." << std::endl; }   // 4. 计算重投影矩阵Q cv::Mat K1, R1, t1, K2, R2, t2; cv::decomposeProjectionMatrix(P1, K1, R1, t1); cv::decomposeProjectionMatrix(P2, K2, R2, t2);   // 转换为非齐次坐标 t1 = t1.rowRange(0, 3) / t1.at<double>(3); t2 = t2.rowRange(0, 3) / t2.at<double>(3);   // 计算基线长度(单位:世界坐标单位) cv::Mat C1 = -R1.inv() * t1; cv::Mat C2 = -R2.inv() * t2; double Tx = cv::norm(C2 - C1);   // 提取内参参数 double fx = K1.at<double>(0, 0); double fy = K1.at<double>(1, 1); double cx = K1.at<double>(0, 2); double cy = K1.at<double>(1, 2);   std::cout << "\nCamera Parameters:" << std::endl; std::cout << " Focal length (fx, fy): " << fx << ", " << fy << std::endl; std::cout << " Principal point (cx, cy): " << cx << ", " << cy << std::endl; std::cout << " Baseline (Tx): " << Tx << " world units" << std::endl;   // 修改Q矩阵构造 double cx_right = K2.at<double>(0, 2); // 右相机主点x cv::Mat Q = (cv::Mat_<double>(4, 4) << 1.0, 0.0, 0.0, -cx, 0.0, 1.0, 0.0, -cy, 0.0, 0.0, 0.0, fx, 0.0, 0.0, -1.0 / Tx, (cx - cx_right) / Tx); // 关键修改   std::cout << "\nReprojection Matrix Q:" << std::endl; std::cout << Q << std::endl;   // 6. 处理视差图 - 关键步骤! cv::Mat disp_float;   // 修改视差图处理部分 double scale_factor = 1.0; if (disparity.type() == CV_16UC1) { scale_factor = 1.0 / 16.0; } else if (disparity.type() == CV_16SC1) { scale_factor = 1.0 / 16.0; } else if (disparity.type() == CV_32FC1) { // 显式匹配32FC1 scale_factor = 1.0; } else if (disparity.type() == CV_32F) { // 后备匹配通用浮点 scale_factor = 1.0; } else { std::cerr << "Warning: Unknown disparity format. Using default scaling." << std::endl; scale_factor = 1.0 / 16.0; } disparity.convertTo(disp_float, CV_32F, scale_factor);   // 7. 计算3D点云 cv::Mat xyz; cv::reprojectImageTo3D(disp_float, xyz, Q, false, CV_32F);   // 8. 提取深度图(Z通道) std::vector<cv::Mat> channels; cv::split(xyz, channels); cv::Mat depth = channels[2];   // 修改深度图可视化部分 cv::Mat depthVis; double minVal, maxVal;   // 创建掩码:有效点 = (深度>0) 且 (非无穷大) cv::Mat validMask = (depth > 0) & (depth < std::numeric_limits<float>::infinity()); cv::Mat validMask8U; validMask.convertTo(validMask8U, CV_8U);   // 仅对有效点计算深度范围 cv::minMaxLoc(depth, &minVal, &maxVal, nullptr, nullptr, validMask8U); std::cout << "Valid Depth Range: min = " << minVal << ", max = " << maxVal << std::endl;   if (maxVal > minVal) { // 归一化有效点到[0, 255] cv::Mat temp = cv::Mat::zeros(depth.size(), CV_32F); depth.copyTo(temp, validMask8U); // 仅复制有效点 temp.convertTo(depthVis, CV_8U, 255.0 / (maxVal - minVal), -minVal * 255.0 / (maxVal - minVal)); } else { depthVis = cv::Mat::zeros(depth.size(), CV_8U); }   cv::imwrite("depth_map.png", depthVis);   // 10. 生成彩色点云(使用二进制PLY格式) savePointCloudToPLY(xyz, leftImage, "point_cloud.ply");   std::cout << "\nProcessing completed." << std::endl; std::cout << "Depth map saved as 'depth_map.png'" << std::endl; std::cout << "Point cloud saved as 'point_cloud.ply'" << std::endl;   cv::waitKey(0); return 0; }这是一段生成深度图和三位点云的代码,但是生成的三维点云质量很差,你帮我重新写一段C++代码,运行出高精度的三位点云

#include <iostream> #include "SerialPort.hpp" #include "Vision.hpp" #include <cstring> #include <string> #include "pid.hpp" #include <stdio.h> #include <cmath> extern SP::SerialPort serial; // 修改为你的串口设备 extern char msg[6]; //extern pid::PIDCLASS pid1; pid::PIDCLASS pid1( 1.40F, 0, 0.060F, 100.0F, 100.0F, -100.0F, 0.040F ); double th = 20;/* 二值化阈值 */ float Xposition = 0; float pidoutput = 0; int pidoutINT = 0; u_int8_t MX = 125; char STR[20]={0}; int main() { cv::VideoCapture Camera01;/* 定义相机 */ cv::Mat Picture0,Picture_B,Picture_Gray,inary,Picture_Binary_Deal,Picture_Binary_Deal_ROI, Picture_Binary_Deal_ROI_L,Picture_Binary_Deal_ROI_R,Picture_Binary;/* 定义图片 */ Camera01.open(0);/* 打开系统视频设备0 */ if( !Camera01.isOpened() ){std::cout<<"初始化时相机打开失败"<<std::endl;return -1;}/* 相机打开失败时 结束程序 */ Camera01.set(cv::CAP_PROP_FRAME_WIDTH,320);/* 设置相机分辨率 */ Camera01.set(cv::CAP_PROP_FRAME_HEIGHT,240); //uart_init(); uart_init(); while( Camera01.read(Picture0) ){ /* 读取图片到Picture0 */ int keyvalue = 0; usleep(40000);/* 40000us=40ms 休眠 */ cv::cvtColor(Picture0, Picture_Gray, cv::COLOR_BGR2GRAY);/* 灰度化 */ cv::threshold(Picture_Gray, Picture_Binary, th, 255, cv::THRESH_BINARY_INV); // 反二值化,黑线变白 cv::Mat Picture_element = cv::getStructuringElement(cv::MORPH_RECT,cv::Size(5,5));//形态学操作 cv::morphologyEx(Picture_Binary, Picture_Binary_Deal, cv::MORPH_OPEN, Picture_element);//开运算 cv::Rect rect_roizone = cv::Rect(0,Picture_Binary_Deal.size().height/2, Picture_Binary_Deal.size().width,Picture_Binary_Deal.size().height/2); Picture_Binary_Deal_ROI = Picture_Binary_Deal( rect_roizone ); /* 设定两个ROI */ cv::Rect rect_roizone_Left = cv::Rect(0,0, Picture_Binary_Deal_ROI.size().width/2,Picture_Binary_Deal_ROI.size().height); cv::Rect rect_roizone_Right = cv::Rect( Picture_Binary_Deal_ROI.size().width/2 , 0 , Picture_Binary_Deal_ROI.size().width/2,Picture_Binary_Deal_ROI.size().height); Picture_Binary_Deal_ROI_L = Picture_Binary_Deal_ROI( rect_roizone_Left );/* 设定下半部分屏幕1/3 2/3区域为ROI */ Picture_Binary_Deal_ROI_R = Picture_Binary_Deal_ROI( rect_roizone_Right ); cv::Moments Moment1 = cv::moments(Picture_Binary_Deal_ROI,true);/* 算质心 */ cv::Moments Moment1L = cv::moments(Picture_Binary_Deal_ROI_L,true);/* 算左侧质心 */ cv::Moments Moment1R = cv::moments(Picture_Binary_Deal_ROI_R,true);/* 算右侧质心 */ float XmL = (float)(Moment1L.m10/Moment1L.m00), XmR = (float)(Moment1R.m10/Moment1R.m00); float temp= (float)(Moment1.m10/Moment1.m00); if( std::isnan(temp) ){ Xposition=0; } else{Xposition = temp;} //Xposition = /* 获得车道的X坐标 */ cv::Point p01( Xposition, Moment1.m01/Moment1.m00 + Picture_Binary.size().height/2);/* 求质心点 */ //cv::Point p01(Moment1.m10/Moment1.m00,Picture_Binary_Deal.size().height/2+Picture_Binary.size().height/2);/* 质心 */ pidoutput = pid1.pidf( (float)(Picture_Binary.size().width/2),(float)(Xposition) ); pidoutINT = (int)(pidoutput); std::cout << "pidout:"<0 50-> -70 由于\0是字符串结束符 故不能发送0 */ if(MX<1){ MX=1;}if(MX>255){MX=255;} sprintf(STR,"pidour:%d ",pidoutINT); cv::Point p03( XmL , Picture_Binary.size().height/2+Moment1L.m01/Moment1L.m00); cv::Point p04( Picture_Binary.size().width/2+XmR , Picture_Binary.size().height/2+Moment1R.m01/Moment1R.m00); cv::Point p00( Picture_Binary.size().width/2 , Picture_Binary.size().height ); cv::Point p02( Picture_Binary.size().width/2 + pidoutINT, Moment1.m01/Moment1.m00 + Picture_Binary.size().height/2);/* pid输出以点的形式呈现 */ cv::rectangle(Picture0,rect_roizone,cv::Scalar(165,0,0),2); cv::circle(Picture0, p02, 4, cv::Scalar(255, 0, 0), 2);/* 画点 */ cv::circle(Picture0, p01, 8, cv::Scalar(0, 255, 0), 2);/* 画点 */ cv::circle(Picture0, p03, 5, cv::Scalar(200, 233, 0), 1);/* 画左侧质心点 */ cv::circle(Picture0, p04, 5, cv::Scalar(200, 233, 0), 1);/* 画右侧质心点 */ std::cout << "XmL="<<XmL <<" XmR="<< (Picture_Binary.size().width/2+XmR) << std::endl; if( (!std::isnan(XmL)) && (!std::isnan(XmR) )&& (abs(XmL - XmR) > 100.0)) { //std::cout << "两条路" << std::endl; cv::line( Picture0, p00, p03, cv::Scalar(255, 0, 0), 1 ); } cv::line(Picture0, cv::Point( Picture0.size().width/2 , 0 ), cv::Point(Picture0.size().width/2, Picture0.size().height), cv::Scalar(0, 0, 200));/* 画中线 */ cv::putText(Picture0,STR,cv::Point(4,25),cv::FONT_HERSHEY_SIMPLEX,0.5,cv::Scalar_(200,200,100),2,8 ) ; //cv::imshow("WightBlackPic",Picture_Binary_Deal);/* 显示图片 */ cv::imshow("CapPicture",Picture0);/* 显示图片 */ cv::imshow("ROI",Picture_Binary_Deal_ROI);/* 显示图片 */ cv::imshow("ROI_Left",Picture_Binary_Deal_ROI_L); cv::imshow("ROI_Right",Picture_Binary_Deal_ROI_R); cv::moveWindow("ROI",450,0);cv::moveWindow("ROI_Left",450,160);cv::moveWindow("ROI_Right",450+320,160); cv::moveWindow("CapPicture",0,0); if( cv::waitKey(1) == 'q' ){std::cout<<"检测到按下q退出"<<std::endl;return 1;}/* 图片显示停留1ms 除非检测到按键'q' 退出程序 */ msg[0]='S'; msg[1]=MX; msg[2]=0xFF; msg[3]=0xFF; msg[4]='E'; //msg[5]=0; uart(); } return 0; }

#include "ucar/ucar.hpp" #include <tf2/LinearMath/Quaternion.h> #include <ros/console.h> FileTransfer::FileTransfer(const std::string& baseDir ) : m_baseDir(baseDir), m_running(false), m_serverThread() { createDirectory(m_baseDir); } FileTransfer::~FileTransfer() { stopServer(); } // 功能1:保存字符串到本地文件 bool FileTransfer::saveToFile(const std::string& content, const std::string& filename) { std::string fullPath = m_baseDir + "/" + filename; std::ofstream file(fullPath); if (!file.is_open()) { std::cerr << "无法打开文件: " << fullPath << std::endl; return false; } file << content; file.close(); std::cout << "文件已保存到: " << fullPath << std::endl; return true; } // 功能2:发送文件到指定IP bool FileTransfer::sendTo(const std::string& serverIP, int port, const std::string& localFile, const std::string& remotePath ) { // 1. 读取文件内容 std::ifstream file(localFile, std::ios::binary | std::ios::ate); if (!file.is_open()) { std::cerr << "无法打开本地文件: " << localFile << std::endl; return false; } size_t fileSize = file.tellg(); file.seekg(0, std::ios::beg); std::vector<char> buffer(fileSize); if (!file.read(buffer.data(), fileSize)) { std::cerr << "读取文件错误: " << localFile << std::endl; return false; } file.close(); // 2. 创建Socket int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { std::cerr << "创建Socket失败: " << strerror(errno) << std::endl; return false; } // 3. 连接服务器 sockaddr_in serverAddr; memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(port); if (inet_pton(AF_INET, serverIP.c_str(), &serverAddr.sin_addr) <= 0) { std::cerr << "无效的IP地址: " << serverIP << std::endl; close(sock); return false; } if (connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { std::cerr << "连接服务器失败: " << strerror(errno) << std::endl; close(sock); return false; } // 4. 发送文件信息 if (!sendData(sock, remotePath, buffer.data(), fileSize)) { close(sock); return false; } close(sock); std::cout << "文件已发送到 " << serverIP << ":" << port << " 保存为 " << remotePath << std::endl; return true; } // 功能3:阻塞等待接收文件并读取内容 std::string FileTransfer::receiveAndRead(int port, int timeoutMs ) { // 确保服务器正在运行 if (!m_running) { startServer(port); } // 等待文件到达 ReceivedFile file; if (!waitForFile(file, timeoutMs)) { throw std::runtime_error("等待文件超时或服务器停止"); } stopServer(); // 返回文件内容 return std::string(file.content.data(), file.content.size()); } // 启动服务器(后台线程) void FileTransfer::startServer(int port) { if (m_running) { stopServer(); } m_running = true; m_serverThread = std::thread(&FileTransfer::serverThreadFunc, this, port); } // 停止服务器 void FileTransfer::stopServer() { if (m_running) { m_running = false; if (m_serverThread.joinable()) { m_serverThread.join(); } } } // 创建目录 bool FileTransfer::createDirectory(const std::string& path) { if (mkdir(path.c_str(), 0777) == -1 && errno != EEXIST) { std::cerr << "无法创建目录: " << path << " - " << strerror(errno) << std::endl; return false; } return true; } // 发送数据到socket bool FileTransfer::sendData(int sock, const std::string& remotePath, const char* data, size_t size) { // 1. 发送路径长度和路径 uint32_t pathLen = htonl(static_cast<uint32_t>(remotePath.size())); if (send(sock, &pathLen, sizeof(pathLen), 0) != sizeof(pathLen)) { std::cerr << "发送路径长度失败" << std::endl; return false; } if (send(sock, remotePath.c_str(), remotePath.size(), 0) != static_cast<ssize_t>(remotePath.size())) { std::cerr << "发送路径失败" << std::endl; return false; } // 2. 发送文件长度和内容 uint32_t netSize = htonl(static_cast<uint32_t>(size)); if (send(sock, &netSize, sizeof(netSize), 0) != sizeof(netSize)) { std::cerr << "发送文件长度失败" << std::endl; return false; } ssize_t totalSent = 0; while (totalSent < static_cast<ssize_t>(size)) { ssize_t sent = send(sock, data + totalSent, size - totalSent, 0); if (sent < 0) { std::cerr << "发送文件内容失败: " << strerror(errno) << std::endl; return false; } totalSent += sent; } return true; } // 服务器线程函数 void FileTransfer::serverThreadFunc(int port) { // 1. 创建Socket int listenSock = socket(AF_INET, SOCK_STREAM, 0); if (listenSock < 0) { std::cerr << "创建Socket失败: " << strerror(errno) << std::endl; return; } // 2. 设置SO_REUSEADDR int opt = 1; setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); // 3. 绑定端口 sockaddr_in serverAddr; memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(port); if (bind(listenSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { std::cerr << "绑定端口失败: " << strerror(errno) << std::endl; close(listenSock); return; } // 4. 开始监听 if (listen(listenSock, 5) < 0) { std::cerr << "监听失败: " << strerror(errno) << std::endl; close(listenSock); return; } std::cout << "文件接收服务器启动,监听端口: " << port << std::endl; // 5. 接受连接循环 bool receivedFile = false; while (m_running&& !receivedFile) { // 设置超时以定期检查停止条件 fd_set readSet; FD_ZERO(&readSet); FD_SET(listenSock, &readSet); timeval timeout{0, 100000}; // 100ms int ready = select(listenSock + 1, &readSet, nullptr, nullptr, &timeout); if (ready < 0) { if (errno != EINTR) { std::cerr << "select错误: " << strerror(errno) << std::endl; } continue; } if (ready == 0) continue; // 超时,继续循环 // 6. 接受客户端连接 sockaddr_in clientAddr; socklen_t clientLen = sizeof(clientAddr); int clientSock = accept(listenSock, (sockaddr*)&clientAddr, &clientLen); if (clientSock < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { std::cerr << "接受连接失败: " << strerror(errno) << std::endl; } continue; } char clientIP[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, INET_ADDRSTRLEN); std::cout << "收到来自 " << clientIP << " 的文件传输请求" << std::endl; // 7. 接收文件 ReceivedFile file; if (receiveFile(clientSock, file)) { std::lock_guard<std::mutex> lock(m_mutex); m_receivedFiles.push(std::move(file)); receivedFile = true; m_cv.notify_one(); // 通知等待线程 } close(clientSock); } close(listenSock); std::cout << "文件接收服务器已停止" << std::endl; } // 接收文件 bool FileTransfer::receiveFile(int sock, ReceivedFile& file) { // 1. 接收路径长度和路径 uint32_t pathLen; if (recv(sock, &pathLen, sizeof(pathLen), 0) != sizeof(pathLen)) { std::cerr << "接收路径长度失败" << std::endl; return false; } pathLen = ntohl(pathLen); std::vector<char> pathBuffer(pathLen + 1); ssize_t received = recv(sock, pathBuffer.data(), pathLen, 0); if (received != static_cast<ssize_t>(pathLen)) { std::cerr << "接收路径失败" << std::endl; return false; } pathBuffer[pathLen] = '\0'; file.filename = pathBuffer.data(); // 2. 接收文件长度 uint32_t fileSize; if (recv(sock, &fileSize, sizeof(fileSize), 0) != sizeof(fileSize)) { std::cerr << "接收文件长度失败" << std::endl; return false; } fileSize = ntohl(fileSize); // 3. 接收文件内容 file.content.resize(fileSize); ssize_t totalReceived = 0; while (totalReceived < static_cast<ssize_t>(fileSize) && m_running) { ssize_t bytes = recv(sock, file.content.data() + totalReceived, fileSize - totalReceived, 0); if (bytes <= 0) { if (bytes < 0) { std::cerr << "接收文件内容失败: " << strerror(errno) << std::endl; } return false; } totalReceived += bytes; } std::cout << "成功接收文件: " << file.filename << " (" << fileSize << " 字节)" << std::endl; return true; } // 等待文件到达 bool FileTransfer::waitForFile(ReceivedFile& file, int timeoutMs) { std::unique_lock<std::mutex> lock(m_mutex); // 只要有文件就立即返回 auto pred = [&] { return !m_receivedFiles.empty(); // 只需检查队列是否非空 }; if (timeoutMs > 0) { if (!m_cv.wait_for(lock, std::chrono::milliseconds(timeoutMs), pred)) { return false; // 超时 } } else { m_cv.wait(lock, pred); } if (m_receivedFiles.empty()) return false; file = std::move(m_receivedFiles.front()); m_receivedFiles.pop(); return true; } // 接收文件并读取两行内容 bool FileTransfer::receiveAndReadTwoStrings(int port, std::string& outStr1, std::string& outStr2, int timeoutMs) { // 确保服务器正在运行 if (!m_running) { startServer(port); } // 等待文件到达 ReceivedFile file; if (!waitForFile(file, timeoutMs)) { throw std::runtime_error("等待文件超时或服务器停止"); } // 读取文件内容 std::string content(file.content.data(), file.content.size()); // 查找第一行结尾 size_t pos = content.find('\n'); if (pos == std::string::npos) { // 没有换行符,整个内容作为第一行 outStr1 = content; outStr2 = ""; } else { // 提取第一行 outStr1 = content.substr(0, pos); // 提取第二行(跳过换行符) outStr2 = content.substr(pos + 1); // 移除第二行可能的多余换行符 if (!outStr2.empty() && outStr2.back() == '\n') { outStr2.pop_back(); } } return true; } bool Ucar::navigateTo(const geometry_msgs::Pose& target) { move_base_msgs::MoveBaseGoal goal; goal.target_pose.header.frame_id = "map"; goal.target_pose.pose = target; move_base_client_.sendGoal(goal); return move_base_client_.waitForResult(navigation_timeout_); } // void Ucar::recovery() { // setlocale(LC_ALL, ""); // std_srvs::Empty srv; // if (clear_costmaps_client_.call(srv)) { // ROS_INFO("代价地图清除成功"); // } else { // ROS_ERROR("代价地图清除服务调用失败"); // } // } Ucar::Ucar(ros::NodeHandle& nh) : nh_(nh), retry_count_(0), current_state_(State::INIT) , control_rate_(10) ,move_base_client_("move_base", true) { latest_odom_.reset(); // 等待move_base服务器就绪(参考网页6的actionlib使用规范) if(!move_base_client_.waitForServer(ros::Duration(5.0))) { setlocale(LC_ALL, ""); ROS_ERROR("无法连接move_base服务器"); } scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1); // 初始化代价地图清除服务 clear_costmaps_client_ = nh_.serviceClient<std_srvs::Empty>("/move_base/clear_costmaps"); setlocale(LC_ALL, ""); // 标记所有的点位总共21个点位 nh_.param("pose1_x", pose_1.position.x, 1.67); nh_.param("pose1_y", pose_1.position.y, 0.04); pose_1.orientation.x = 0.0; pose_1.orientation.y = 0.0; pose_1.orientation.z = 0.707; pose_1.orientation.w = 0.707; nh_.param("pose2_x", pose_2.position.x, 1.83); nh_.param("pose2_y", pose_2.position.y, 0.380); pose_2.orientation.x = 0.0; pose_2.orientation.y = 0.0; pose_2.orientation.z = 1; pose_2.orientation.w = 0; nh_.param("pose3_x", pose_3.position.x, 1.0); nh_.param("pose3_y", pose_3.position.y, 0.494); pose_3.orientation.x = 0.0; pose_3.orientation.y = 0.0; pose_3.orientation.z = 1; pose_3.orientation.w = 0; nh_.param("pose4_x", pose_4.position.x, 0.15166891130059032); nh_.param("pose4_y", pose_4.position.y, 0.5446138339072089); pose_4.orientation.x = 0.0; pose_4.orientation.y = 0.0; pose_4.orientation.z = 0.707; pose_4.orientation.w = 0.707; nh_.param("pose5_x", pose_5.position.x, 0.387605134459779); nh_.param("pose5_y", pose_5.position.y, 0.949243539748394); pose_5.orientation.x = 0.0; pose_5.orientation.y = 0.0; pose_5.orientation.z = 0.0; pose_5.orientation.w = 1.0; nh_.param("pose6_x", pose_6.position.x, 1.0250469329539987); nh_.param("pose6_y", pose_6.position.y, 1.0430107266961729); pose_6.orientation.x = 0.0; pose_6.orientation.y = 0.0; pose_6.orientation.z = 0.0; pose_6.orientation.w = 1.0; nh_.param("pose7_x", pose_7.position.x, 1.715746358650675); nh_.param("pose7_y", pose_7.position.y, 1.0451169673664757); pose_7.orientation.x = 0.0; pose_7.orientation.y = 0.0; pose_7.orientation.z = 0.707; pose_7.orientation.w = 0.707; nh_.param("pose8_x", pose_8.position.x, 1.820954899866641); nh_.param("pose8_y", pose_8.position.y, 1.405578846446346); pose_8.orientation.x = 0.0; pose_8.orientation.y = 0.0; pose_8.orientation.z = 1; pose_8.orientation.w = 0; nh_.param("pose9_x", pose_9.position.x, 1.287663212010699); nh_.param("pose9_y", pose_9.position.y, 1.4502232396357953); pose_9.orientation.x = 0.0; pose_9.orientation.y = 0.0; pose_9.orientation.z = 1; pose_9.orientation.w = 0; nh_.param("pose10_x", pose_10.position.x, 0.433025661760874); nh_.param("pose10_y", pose_10.position.y, 1.5362058814619577); pose_10.orientation.x = 0.0; pose_10.orientation.y = 0.0; pose_10.orientation.z = 0.707; pose_10.orientation.w = 0.707; //开始进入视觉定位区域 中心点加上四个中线点对应四面墙 nh_.param("pose_center_x", pose_11.position.x, 1.13); nh_.param("pose_center_y", pose_11.position.y, 3.04); nh_.param("pose_center_x", pose_12.position.x, 1.13); nh_.param("pose_center_y", pose_12.position.y, 3.04); nh_.param("pose_center_x", pose_13.position.x, 1.13); nh_.param("pose_center_y", pose_13.position.y, 3.04); nh_.param("pose_center_x", pose_14.position.x, 1.13); nh_.param("pose_center_y", pose_14.position.y, 3.04); nh_.param("pose_center_x", pose_15.position.x, 1.13); nh_.param("pose_center_y", pose_15.position.y, 3.04); //退出视觉区域进入路灯识别区域 nh_.param("pose_center_x", pose_16.position.x, 1.13); nh_.param("pose_center_y", pose_16.position.y, 3.04); nh_.param("pose_center_x", pose_17.position.x, 1.13); nh_.param("pose_center_y", pose_17.position.y, 3.04); nh_.param("pose_center_x", pose_18.position.x, 1.13); nh_.param("pose_center_y", pose_18.position.y, 3.04); //退出路灯识别区域,进入巡线区域 注意两个点位取一个,必须标定正确的方向 nh_.param("pose_center_x", pose_19.position.x, 1.13); nh_.param("pose_center_y", pose_19.position.y, 3.04); pose_19.orientation.x = 0.0; pose_19.orientation.y = 0.0; pose_19.orientation.z = 0.707; pose_19.orientation.w = 0.707; nh_.param("pose_center_x", pose_20.position.x, 1.13); nh_.param("pose_center_y", pose_20.position.y, 3.04); pose_20.orientation.x = 0.0; pose_20.orientation.y = 0.0; pose_20.orientation.z = 0.707; pose_20.orientation.w = 0.707; //result_sub_ = nh_.subscribe("result_of_object", 1, &Ucar::detectionCallback, this); result_client_ = nh_.serviceClient<rfbot_yolov8_ros::DetectGood>("object_realsense_recognization"); cmd_vel_pub = nh_.advertise<geometry_msgs::Twist>("/cmd_vel", 10); odom_sub = nh_.subscribe("/odom", 10, &Ucar::odomCallback, this); interaction_client = nh_.serviceClient<ucar::ObjectDetection>("object_detection"); ROS_INFO_STREAM("状态机初始化完成"); } void Ucar::navigate_to_aruco_place(){ setlocale(LC_ALL, ""); navigateTo(pose_1);ROS_INFO("到达pose_1"); navigateTo(pose_2);ROS_INFO("到达pose_2"); navigateTo(pose_3);ROS_INFO("到达pose_3"); } void Ucar::navigate_to_recongnition_place(){ setlocale(LC_ALL, ""); navigateTo(pose_4);ROS_INFO("到达pose_4"); navigateTo(pose_5);ROS_INFO("到达pose_5"); navigateTo(pose_6);ROS_INFO("到达pose_6"); navigateTo(pose_7);ROS_INFO("到达pose_7"); navigateTo(pose_8);ROS_INFO("到达pose_8"); navigateTo(pose_9);ROS_INFO("到达pose_9"); navigateTo(pose_10);ROS_INFO("到达pose_10"); } void Ucar::run() { while (ros::ok()) { ros::spinOnce(); switch(current_state_) { case State::INIT: {handleInit(); break;} case State::ARUCO: {navigate_to_aruco_place(); ROS_INFO("导航到二维码区域"); see_aruco(); if(target_object=="vegetable") playAudioFile("/home/ucar/ucar_ws/src/wav/sc.wav"); if(target_object=="fruit") playAudioFile("/home/ucar/ucar_ws/src/wav/sg.wav"); if(target_object=="dessert") playAudioFile("/home/ucar/ucar_ws/src/wav/tp.wav"); break;} case State::FIND: {navigate_to_recongnition_place(); spin_to_find();//转着找目标 break;} case State::GAZEBO: {gazebo(); break;} } control_rate_.sleep(); } } void Ucar::handleInit() { setlocale(LC_ALL, ""); ROS_DEBUG("执行初始化流程"); current_state_ = State::ARUCO; } void Ucar::see_aruco() { qr_found_ = false; image_transport::ImageTransport it(nh_); // 2. 创建订阅器,订阅/usb_cam/image_raw话题 image_transport::Subscriber sub = it.subscribe( "/usb_cam/image_raw", 1, &Ucar::imageCallback, this ); std::cout << "已订阅摄像头话题,等待图像数据..." << std::endl; // 3. 创建ZBar扫描器 scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1); target_object = ""; // 重置结果 // 4. 设置超时检测 const int MAX_SCAN_DURATION = 30; // 最大扫描时间(秒) auto scan_start_time = std::chrono::steady_clock::now(); // 5. ROS事件循环 ros::Rate loop_rate(30); // 30Hz while (ros::ok() && !qr_found_) { // 检查超时 auto elapsed = std::chrono::steady_clock::now() - scan_start_time; if (std::chrono::duration_cast<std::chrono::seconds>(elapsed).count() > MAX_SCAN_DURATION) { std::cout << "扫描超时" << std::endl; break; } ros::spinOnce(); loop_rate.sleep(); } // 6. 清理资源 if (!qr_found_) target_object = ""; } void Ucar::imageCallback(const sensor_msgs::ImageConstPtr& msg) { try { // 7. 将ROS图像消息转换为OpenCV格式 cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8); cv::Mat frame = cv_ptr->image; cv::Mat gray; cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY); // 8. 准备ZBar图像 cv::Mat gray_cont = gray.clone(); zbar::Image image(gray.cols, gray.rows, "Y800", gray_cont.data, gray.cols * gray.rows); // 9. 扫描二维码 if (scanner.scan(image) >= 0) { for (zbar::Image::SymbolIterator symbol = image.symbol_begin(); symbol != image.symbol_end(); ++symbol) { // 获取原始结果 std::string rawResult = symbol->get_data(); // 在存储到全局变量前将首字母转换为小写 target_object = toLowerFirstChar(rawResult); ROS_INFO("识别到二维码: %s", target_object.c_str()); current_state_ = State::FIND; qr_found_ = true; // 在视频帧上绘制结果 std::vector<cv::Point> points; for (int i = 0; i < symbol->get_location_size(); i++) { points.push_back(cv::Point(symbol->get_location_x(i), symbol->get_location_y(i))); } // 绘制二维码边界框 cv::RotatedRect rect = cv::minAreaRect(points); cv::Point2f vertices[4]; rect.points(vertices); for (int i = 0; i < 4; i++) { cv::line(frame, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 255, 0), 2); } // 显示原始二维码内容 cv::putText(frame, rawResult, cv::Point(10, 30), cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 255, 0), 2); // 显示转换后的结果 cv::putText(frame, "Stored: " + target_object, cv::Point(10, 60), cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 0, 255), 2); // 显示最终结果画面 cv::imshow("QR Code Scanner", frame); cv::waitKey(250); // 短暂显示结果 } } // 显示当前帧 cv::imshow("QR Code Scanner", frame); cv::waitKey(1); } catch (cv_bridge::Exception& e) { ROS_ERROR("cv_bridge异常: %s", e.what()); } } //播放音频文件函数 bool Ucar::playAudioFile(const std::string& filePath) { // 创建子进程播放音频 pid_t pid = fork(); if (pid == 0) { // 子进程 // 尝试使用 aplay (适用于 WAV 文件) execlp("aplay", "aplay", "-q", filePath.c_str(), (char*)NULL); // 如果 aplay 失败,尝试 ffplay execlp("ffplay", "ffplay", "-nodisp", "-autoexit", "-loglevel", "quiet", filePath.c_str(), (char*)NULL); // 如果 ffplay 失败,尝试 mpg123 (适用于 MP3) execlp("mpg123", "mpg123", "-q", filePath.c_str(), (char*)NULL); // 如果所有播放器都不可用,退出 exit(1); } else if (pid > 0) { // 父进程 int status; waitpid(pid, &status, 0); return WIFEXITED(status) && WEXITSTATUS(status) == 0; } else { // fork 失败 perror("fork failed"); return false; } } // 辅助函数:将字符串首字母转换为小写 std::string Ucar::toLowerFirstChar(const std::string& str) { if (str.empty()) return str; std::string result = str; result[0] = static_cast<char>(std::tolower(static_cast<unsigned char>(result[0]))); return result; } // 在odomCallback中更新最新里程计数据 void Ucar::odomCallback(const nav_msgs::Odometry::ConstPtr& msg) { latest_odom_ = msg; // 保存最新里程计数据 if (!position_recorded) { initial_position = msg->pose.pose.position; position_recorded = true; //ROS_INFO("初始位置记录完成: (%.3f, %.3f)", // initial_position.x, initial_position.y); } } void Ucar::moveLeftDistance(double distance_m, double linear_speed) { // 订阅里程计话题(根据实际机器人配置修改话题名) // 等待位置记录完成 position_recorded = false; while (!position_recorded && ros::ok()) { ros::spinOnce(); ros::Duration(0.1).sleep(); } // 计算理论运动时间 double duration = distance_m / linear_speed; //ROS_INFO("开始左移: 距离=%.2fm, 速度=%.2fm/s, 理论时间=%.1fs", // distance_m, linear_speed, duration); // 创建控制消息 geometry_msgs::Twist move_cmd; move_cmd.linear.y = linear_speed; // 全向移动Y轴速度控制左右移动 // 记录开始时间 auto start_time = ros::Time::now(); // 持续发送控制命令 while ((ros::Time::now() - start_time).toSec() < duration && ros::ok()) { cmd_vel_pub.publish(move_cmd); ros::Duration(0.05).sleep(); // 50ms控制周期 } // 发送停止指令 move_cmd.linear.y = 0; cmd_vel_pub.publish(move_cmd); //ROS_INFO("左移完成"); } void Ucar::moveRightDistance(double distance_m, double linear_speed) { // 等待位置记录完成 position_recorded = false; while (!position_recorded && ros::ok()) { ros::spinOnce(); ros::Duration(0.1).sleep(); } // 计算理论运动时间 double duration = distance_m / linear_speed; //ROS_INFO("开始右移: 距离=%.2fm, 速度=%.2fm/s, 理论时间=%.1fs", // distance_m, linear_speed, duration); // 创建控制消息 geometry_msgs::Twist move_cmd; move_cmd.linear.y = -linear_speed; // 全向移动Y轴速度控制左右移动 // 记录开始时间 auto start_time = ros::Time::now(); // 持续发送控制命令 while ((ros::Time::now() - start_time).toSec() < duration && ros::ok()) { cmd_vel_pub.publish(move_cmd); ros::Duration(0.05).sleep(); // 50ms控制周期 } // 发送停止指令 move_cmd.linear.y = 0; cmd_vel_pub.publish(move_cmd); //ROS_INFO("右移完成"); } void Ucar::moveForwardDistance(double distance_m, double linear_speed) { // 确保速度为正值(前进方向) if (linear_speed < 0) { ROS_WARN("前进速度应为正值,自动取绝对值"); linear_speed = fabs(linear_speed); } // 等待位置记录完成 position_recorded = false; while (!position_recorded && ros::ok()) { ros::spinOnce(); ros::Duration(0.1).sleep(); } // 计算理论运动时间 double duration = distance_m / linear_speed; //ROS_INFO("开始前进: 距离=%.2fm, 速度=%.2fm/s, 理论时间=%.1fs", // distance_m, linear_speed, duration); // 创建控制消息 geometry_msgs::Twist move_cmd; move_cmd.linear.x = linear_speed; // X轴速度控制前后移动 // 记录开始时间 auto start_time = ros::Time::now(); // 持续发送控制命令 while ((ros::Time::now() - start_time).toSec() < duration && ros::ok()) { cmd_vel_pub.publish(move_cmd); ros::Duration(0.05).sleep(); // 50ms控制周期 } // 发送停止指令 move_cmd.linear.x = 0.0; cmd_vel_pub.publish(move_cmd); ROS_INFO("前进完成"); } //输入1逆时针,输入-1顺时针 void Ucar::rotateCounterClockwise5Degrees(int a) { // 设置旋转参数 const double angular_speed = 0.2; // rad/s (约11.5度/秒) const double degrees = 5.0; const double duration = degrees * (M_PI / 180.0) / angular_speed; // 约0.436秒 //if(a==1) //ROS_INFO("开始逆时针旋转5度: 速度=%.2f rad/s, 时间=%.3f秒", // angular_speed, duration); //else if(a==-1) //ROS_INFO("开始顺时针旋转5度: 速度=%.2f rad/s, 时间=%.3f秒", // angular_speed, duration); // 创建控制消息 geometry_msgs::Twist twist_msg; twist_msg.angular.z = angular_speed*a; // 正值表示逆时针 // 记录开始时间 auto start_time = ros::Time::now(); // 持续发送控制命令 while ((ros::Time::now() - start_time).toSec() < duration && ros::ok()) { cmd_vel_pub.publish(twist_msg); ros::Duration(0.05).sleep(); // 20Hz控制周期 } // 发送停止命令(确保接收) twist_msg.angular.z = 0.0; for (int i = 0; i < 3; i++) { cmd_vel_pub.publish(twist_msg); ros::Duration(0.02).sleep(); } if(a==1) ROS_INFO("逆时针旋转5度完成"); else if (a==-1) ROS_INFO("顺时针旋转5度完成"); } void Ucar::rotateCounterClockwise360Degrees() { // 设置旋转参数 const double angular_speed = 1; // rad/s (约11.5度/秒) const double degrees = 360.0; const double duration = degrees * (M_PI / 180.0) / angular_speed; // 约0.436秒 // 创建控制消息 geometry_msgs::Twist twist_msg; twist_msg.angular.z = angular_speed; // 正值表示逆时针 // 记录开始时间 auto start_time = ros::Time::now(); // 持续发送控制命令 while ((ros::Time::now() - start_time).toSec() < duration && ros::ok()) { cmd_vel_pub.publish(twist_msg); ros::Duration(0.05).sleep(); // 20Hz控制周期 } // 发送停止命令(确保接收) twist_msg.angular.z = 0.0; for (int i = 0; i < 3; i++) { cmd_vel_pub.publish(twist_msg); ros::Duration(0.02).sleep(); } } void Ucar::left_and_right_move_old(){ rfbot_yolov8_ros::DetectGood srv; while((find_object_x2_old+find_object_x1_old)/2>324){ if((find_object_x2_old+find_object_x1_old)>340) moveLeftDistance(0.15,0.1);//控制小车往左移动15cm else moveLeftDistance(0.05,0.1);//控制小车往左移动5cm moveForwardDistance(0.05,0.1); Ucar::result_client_.call(srv); for (size_t j = 0; j < srv.response.goodName.size(); ++j) { ROS_INFO("响应结果:"); ROS_INFO("位置: x1: %d, y1: %d, x2: %d, y2: %d", srv.response.u1[j], srv.response.v1[j], srv.response.u2[j], srv.response.v2[j]); //ROS_INFO("置信度: %f", srv.response.confidence[j]); find_object_x1_old=srv.response.u1[0]; find_object_y1_old=srv.response.v1[0]; find_object_x2_old=srv.response.u2[0]; find_object_y2_old=srv.response.v2[0]; } ROS_INFO("当前目标中心横坐标为:%d",(find_object_x2_old+find_object_x1_old)/2); } while((find_object_x2_old+find_object_x1_old)/2<316){ if((find_object_x2_old+find_object_x1_old)<300) moveRightDistance(0.15,0.1);//控制小车往右移动15cm else moveRightDistance(0.05,0.1);//控制小车往右移动5cm moveForwardDistance(0.05,0.1); Ucar::result_client_.call(srv); for (size_t j = 0; j < srv.response.goodName.size(); ++j) { ROS_INFO("响应结果:"); ROS_INFO("位置: x1: %d, y1: %d, x2: %d, y2: %d", srv.response.u1[j], srv.response.v1[j], srv.response.u2[j], srv.response.v2[j]); //ROS_INFO("置信度: %f", srv.response.confidence[j]); find_object_x1_old=srv.response.u1[0]; find_object_y1_old=srv.response.v1[0]; find_object_x2_old=srv.response.u2[0]; find_object_y2_old=srv.response.v2[0]; } ROS_INFO("当前目标中心横坐标为:%d",(find_object_x2_old+find_object_x1_old)/2); } ROS_INFO("左右移动完成"); } //前进函数(涵盖第二种停靠算法) void Ucar::go(){ rfbot_yolov8_ros::DetectGood srv; while(1){ moveForwardDistance(0.05,0.1);//控制小车前进 Ucar::result_client_.call(srv); for (size_t j = 0; j < srv.response.goodName.size(); ++j) { ROS_INFO("响应结果:"); ROS_INFO("位置: x1: %d, y1: %d, x2: %d, y2: %d", srv.response.u1[j], srv.response.v1[j], srv.response.u2[j], srv.response.v2[j]); //ROS_INFO("置信度: %f", srv.response.confidence[j]); find_object_x1_new=srv.response.u1[0]; find_object_y1_new=srv.response.v1[0]; find_object_x2_new=srv.response.u2[0]; find_object_y2_new=srv.response.v2[0]; } //图像左边先到达边线——>逆时针往右 if(find_object_x2_new==640&&find_object_y1_new==0&&find_object_x1_new!=0&&find_object_y2_new>=350){ if(find_object_x1_new>240||(find_object_x2_new-find_object_x1_new)<=(find_object_y2_new-find_object_y1_new)){ rotateCounterClockwise5Degrees(1); rotateCounterClockwise5Degrees(1); rotateCounterClockwise5Degrees(1); rotateCounterClockwise5Degrees(1); rotateCounterClockwise5Degrees(1); moveRightDistance(0.35,0.1); ROS_INFO("大摆头"); break; } else if(find_object_x1_new>120){ rotateCounterClockwise5Degrees(1); rotateCounterClockwise5Degrees(1); rotateCounterClockwise5Degrees(1); moveRightDistance(0.25,0.1); ROS_INFO("中摆头"); break; } else{ rotateCounterClockwise5Degrees(1);//逆时针 moveRightDistance(0.1,0.1); ROS_INFO("小摆头"); break; } } //图像右边先到达边线——>顺时针往左 else if(find_object_x1_new==0&&find_object_y1_new==0&&find_object_x2_new!=640&&find_object_y2_new>=350){ if(find_object_x2_new<400||(find_object_x2_new-find_object_x1_new)<=(find_object_y2_new-find_object_y1_new)){ rotateCounterClockwise5Degrees(-1); rotateCounterClockwise5Degrees(-1); rotateCounterClockwise5Degrees(-1); rotateCounterClockwise5Degrees(-1); rotateCounterClockwise5Degrees(-1); moveLeftDistance(0.35,0.1); ROS_INFO("大摆头"); break; } else if(find_object_x2_new<520){ rotateCounterClockwise5Degrees(-1); rotateCounterClockwise5Degrees(-1); rotateCounterClockwise5Degrees(-1); moveLeftDistance(0.25,0.1); ROS_INFO("中摆头"); break; } else{ rotateCounterClockwise5Degrees(-1);//顺时针 moveLeftDistance(0.1,0.1); ROS_INFO("小摆头"); break; } } } } void Ucar::visualservo(){ rfbot_yolov8_ros::DetectGood srv; //左移右移 left_and_right_move_old(); //提取长宽比 Ucar::result_client_.call(srv); for (size_t j = 0; j < srv.response.goodName.size(); ++j) { ROS_INFO("响应结果:"); ROS_INFO("位置: x1: %d, y1: %d, x2: %d, y2: %d", srv.response.u1[j], srv.response.v1[j], srv.response.u2[j], srv.response.v2[j]); //ROS_INFO("置信度: %f", srv.response.confidence[j]); find_object_x1_old=srv.response.u1[0]; find_object_y1_old=srv.response.v1[0]; find_object_x2_old=srv.response.u2[0]; find_object_y2_old=srv.response.v2[0]; } changkuanbi_old=(find_object_x2_old-find_object_x1_old)/(find_object_y2_old-find_object_y1_old); ROS_INFO("长宽比为:%f",changkuanbi_old);go(); if(find_object=="dessert1") playAudioFile("/home/ucar/ucar_ws/src/wav/kl.wav"); if(find_object=="dessert2") playAudioFile("/home/ucar/ucar_ws/src/wav/dg.wav"); if(find_object=="dessert3") playAudioFile("/home/ucar/ucar_ws/src/wav/nn.wav"); if(find_object=="vegetable1") playAudioFile("/home/ucar/ucar_ws/src/wav/lj.wav"); if(find_object=="vegetable2") playAudioFile("/home/ucar/ucar_ws/src/wav/xhs.wav"); if(find_object=="vegetable3") playAudioFile("/home/ucar/ucar_ws/src/wav/td.wav"); if(find_object=="fruit1") playAudioFile("/home/ucar/ucar_ws/src/wav/xj.wav"); if(find_object=="fruit2") playAudioFile("/home/ucar/ucar_ws/src/wav/pg.wav"); if(find_object=="fruit3") playAudioFile("/home/ucar/ucar_ws/src/wav/xg.wav"); // if(abs(changkuanbi_old-1.666666667)<0.05){ // ROS_INFO("比较接近16:9,不需要旋转"); // //前进 // go(); // } // else { // //先逆时针转个10度 // rotateCounterClockwise5Degrees(1); // rotateCounterClockwise5Degrees(1); // Ucar::result_client_.call(srv); // for (size_t j = 0; j < srv.response.goodName.size(); ++j) { // ROS_INFO("响应结果:"); // ROS_INFO("位置: x1: %d, y1: %d, x2: %d, y2: %d", // srv.response.u1[j], // srv.response.v1[j], // srv.response.u2[j], // srv.response.v2[j]); // //ROS_INFO("置信度: %f", srv.response.confidence[j]); // find_object_x1_new=srv.response.u1[0]; // find_object_y1_new=srv.response.v1[0]; // find_object_x2_new=srv.response.u2[0]; // find_object_y2_new=srv.response.v2[0]; // } // changkuanbi_new=(find_object_x2_new-find_object_x1_new)/(find_object_y2_new-find_object_y1_new); // ROS_INFO("长宽比为:%f",changkuanbi_new); // if(changkuanbi_new<changkuanbi_old)//方向错了 // { // while(abs(changkuanbi_new-1.666666667)>0.4)//不准就再转 // { // rotateCounterClockwise5Degrees(-1); // Ucar::result_client_.call(srv); // for (size_t j = 0; j < srv.response.goodName.size(); ++j) { // ROS_INFO("响应结果:"); // ROS_INFO("位置: x1: %d, y1: %d, x2: %d, y2: %d", // srv.response.u1[j], // srv.response.v1[j], // srv.response.u2[j], // srv.response.v2[j]); // //ROS_INFO("置信度: %f", srv.response.confidence[j]); // find_object_x1_new=srv.response.u1[0]; // find_object_y1_new=srv.response.v1[0]; // find_object_x2_new=srv.response.u2[0]; // find_object_y2_new=srv.response.v2[0]; // //保持正对目标 // while((find_object_x2_new+find_object_x1_new)/2>324) // {moveLeftDistance(0.05,0.1);//控制小车往左移动5cm // Ucar::result_client_.call(srv); // for (size_t j = 0; j < srv.response.goodName.size(); ++j) { // ROS_INFO("响应结果:"); // ROS_INFO("位置: x1: %d, y1: %d, x2: %d, y2: %d", // srv.response.u1[j], // srv.response.v1[j], // srv.response.u2[j], // srv.response.v2[j]); // //ROS_INFO("置信度: %f", srv.response.confidence[j]); // find_object_x1_new=srv.response.u1[0]; // find_object_y1_new=srv.response.v1[0]; // find_object_x2_new=srv.response.u2[0]; // find_object_y2_new=srv.response.v2[0]; // } // changkuanbi_new=(find_object_x2_new-find_object_x1_new)/(find_object_y2_new-find_object_y1_new); // ROS_INFO("长宽比为:%f",changkuanbi_new);} // while((find_object_x2_new+find_object_x1_new)/2<316) // {moveRightDistance(0.05,0.1);//控制小车往右移动5cm // Ucar::result_client_.call(srv); // for (size_t j = 0; j < srv.response.goodName.size(); ++j) { // ROS_INFO("响应结果:"); // ROS_INFO("位置: x1: %d, y1: %d, x2: %d, y2: %d", // srv.response.u1[j], // srv.response.v1[j], // srv.response.u2[j], // srv.response.v2[j]); // //ROS_INFO("置信度: %f", srv.response.confidence[j]); // find_object_x1_new=srv.response.u1[0]; // find_object_y1_new=srv.response.v1[0]; // find_object_x2_new=srv.response.u2[0]; // find_object_y2_new=srv.response.v2[0]; // } // changkuanbi_new=(find_object_x2_new-find_object_x1_new)/(find_object_y2_new-find_object_y1_new); // ROS_INFO("长宽比为:%f",changkuanbi_new);} // } // } // } // else{//方向对了 // while(abs(changkuanbi_new-1.666666667)>0.4)//不准就再转 // { // rotateCounterClockwise5Degrees(1); // //保持正对目标 // while((find_object_x2_new+find_object_x1_new)/2>324) moveLeftDistance(0.05,0.1);//控制小车往左移动5cm // while((find_object_x2_new+find_object_x1_new)/2<316) moveRightDistance(0.05,0.1);//控制小车往右移动5cm // Ucar::result_client_.call(srv); // for (size_t j = 0; j < srv.response.goodName.size(); ++j) { // ROS_INFO("响应结果:"); // ROS_INFO("位置: x1: %d, y1: %d, x2: %d, y2: %d", // srv.response.u1[j], // srv.response.v1[j], // srv.response.u2[j], // srv.response.v2[j]); // //ROS_INFO("置信度: %f", srv.response.confidence[j]); // find_object_x1_new=srv.response.u1[0]; // find_object_y1_new=srv.response.v1[0]; // find_object_x2_new=srv.response.u2[0]; // find_object_y2_new=srv.response.v2[0]; // } // changkuanbi_new=(find_object_x2_new-find_object_x1_new)/(find_object_y2_new-find_object_y1_new); // ROS_INFO("长宽比为:%f",changkuanbi_new); // } // } // //前进 // go(); // } ROS_INFO("导航完成"); ros::Duration(3000).sleep(); current_state_ = State::GAZEBO; } void Ucar::spin_to_find(){ setlocale(LC_ALL, ""); for(int i=0;i<9;i++){ navigateTo(pose_center[i]);//导航到i号点位 ros::Duration(3).sleep();//停留3秒 rfbot_yolov8_ros::DetectGood srv; Ucar::result_client_.call(srv); for (size_t j = 0; j < srv.response.goodName.size(); ++j) { ROS_INFO("响应结果:"); ROS_INFO("位置: x1: %d, y1: %d, x2: %d, y2: %d", srv.response.u1[j], srv.response.v1[j], srv.response.u2[j], srv.response.v2[j]); //ROS_INFO("置信度: %f", srv.response.confidence[j]); find_object_x1_old=srv.response.u1[0]; find_object_y1_old=srv.response.v1[0]; find_object_x2_old=srv.response.u2[0]; find_object_y2_old=srv.response.v2[0]; pose_center_object[i] = srv.response.goodName[0]; //看看这个方向有没有目标 } if(pose_center_object[i].find(target_object)!=std::string::npos&&(find_object_x2_old-find_object_x1_old)>=(find_object_y2_old-find_object_y1_old)) {ROS_INFO("本次任务目标识别成功"); find_object=pose_center_object[i]; visualservo(); break;} else{ ROS_INFO("本次任务目标识别失败,尝试下一个目标"); continue; } } } void Ucar::gazebo(){ navigateTo(pose_gazebo); //主从机通信 FileTransfer ft("/home/ucar/ucar_ws/src/ucar"); ft.saveToFile(target_object, "target.txt"); //电脑的ip ft.sendTo("192.168.1.100", 8080, "/home/ucar/ucar_ws/src/ucar/target.txt", "/home/zzs/gazebo_test_ws/src/ucar2/target.txt"); try { // 示例3:等待接收文件并读取内容 std::cout << "等待接收文件..." << std::endl; ft.receiveAndReadTwoStrings(8080, gazebo_object, gazebo_room); std::cout << "接收到的内容:\n" << gazebo_object << "\n"<<gazebo_room << std::endl; } catch (const std::exception& e) { std::cerr << "错误: " << e.what() << std::endl;} ros::Duration(30000).sleep();//停留3秒 } int main(int argc, char** argv) { ros::init(argc, argv, "multi_room_navigation_node"); ros::NodeHandle nh; Ucar ucar(nh); ucar.run(); return 0; } 帮我修改上述代码,其中导航到nh_.param("pose_center_x", pose_11.position.x, 1.13); nh_.param("pose_center_y", pose_11.position.y, 3.04); nh_.param("pose_center_x", pose_12.position.x, 1.13); nh_.param("pose_center_y", pose_12.position.y, 3.04); nh_.param("pose_center_x", pose_13.position.x, 1.13); nh_.param("pose_center_y", pose_13.position.y, 3.04); nh_.param("pose_center_x", pose_14.position.x, 1.13); nh_.param("pose_center_y", pose_14.position.y, 3.04); nh_.param("pose_center_x", pose_15.position.x, 1.13); nh_.param("pose_center_y", pose_15.position.y, 3.04);时候时,删除原来旋转十五度停下的情况,改成每个点都停留,然后开始原地旋转,每旋转0.2秒停顿0.5秒,然后旋转360度之后,前往下一个点,在其中任意一个点识别到目标时,就不前往之后的点而是直接进入视觉定位,最后直接前往 nh_.param("pose_center_x", pose_16.position.x, 1.13); nh_.param("pose_center_y", pose_16.position.y, 3.04);

#ifndef ARS_RADAR_H_ #define ARS_RADAR_H_ #include <ros/ros.h> #include <string> #include <vector> #include <thread> //#include"gps_msgs/gpsUtm.h" #include <can_msgs/Object.h> #include <can_msgs/ObjectArray.h> #include <can_msgs/FrameArray.h> #include <jsk_recognition_msgs/BoundingBox.h> #include <jsk_recognition_msgs/BoundingBoxArray.h> #include #include #include <sensor_msgs/PointCloud2.h> #include <diagnostic_msgs/DiagnosticStatus.h> #include <cmath> #include <unordered_map> class ArsRadar { public: ArsRadar(); ~ArsRadar(){ pthread_rwlock_destroy(&egoSpeedLock); pthread_rwlock_destroy(&countLock); }; bool init(); void run(); private: void sendMsgToArs(const ros::TimerEvent&); void configArs(const ros::TimerEvent&); void canMsg_callback(const can_msgs::FrameArray::ConstPtr& msg); //void gps_callback(const gps_msgs::gpsUtm::ConstPtr& msg); void parse_msg(const can_msgs::Frame &frame, int index, int n); void pubBoundingBoxArray(); enum Cluster_DynProp { Target_Move = 0, //移动 Target_Static = 1, //静止 Target_Come = 2, //来向 Target_May_Static = 3, //可能静止 Target_Unknow = 4, //未知 Target_Across = 5, //横穿 Target_Across_Static = 6, //横穿静止 Target_Stop = 7 //停止 }; typedef struct _Info { std::string type; uint8_t r; uint8_t g; uint8_t b; _Info(const std::string& t, uint8_t _r, uint8_t _g, uint8_t _b) { type = t; r = _r; g = _g; b = _b; } }Info; std::vector<Info> Infos; private: ros::Subscriber sub_can_; // 订阅can分析仪消息 ros::Subscriber sub_gps_; ros::Publisher pub_can_; // 向can分析仪发布消息 ros::Publisher pub_can_config; // 向can分析仪发布配置消息 ros::Publisher pub_object_; // 发布离我最近的障碍物消息 ros::Publisher pub_objects_; // 发布所有障碍物消息 ros::Publisher pub_cloud_; // 发布点云消息 pcl::PointCloud cloud; pcl::PointXYZRGB point; sensor_msgs::PointCloud2 output; std::string from_can_topic_; std::string to_can_topic_; std::string gpsUtm_topic; can_msgs::ObjectArray ars_objects_; can_msgs::Object ars_object_; can_msgs::Object ars_object_car; bool is_sendMsgToArs_; ros::Timer timer_1, timer_2; std::unordered_map<int, int> MapObjectId2indexInObjectArray; double egoSpeed; // m/s double yawRate; // deg/s pthread_rwlock_t egoSpeedLock, countLock; int readCount; }; #endif 在此代码上推出上面引用的头文件中#include"gps_msgs/gpsUtm.h"的msgs文件

参考以上文件,用C语言神经网络模型,编写代码,预测成熟度。改成一下几种特征firmness hue saturation brightness color_category sound_db weight_g size_cm3 最后成熟度有5种程度 #include <iostream> #include "rapidcsv.h" #include <opencv2/opencv.hpp> using namespace std; using namespace cv; using namespace cv::ml; typedef struct { double x1,x2,x3,x4; //嘴峰长度、嘴峰深度、脚掌长度、 体重 int x5_0,x5_1; //是否male(1:male,0:female);是否famale(1:female,0:male) int label; //类别标签, 0:Adelie,1:Gentoo,2: Chinstrap } DataPoint; int ReadCsv(const char* fileName, DataPoint data[]) { rapidcsv::Document doc(fileName, rapidcsv::LabelParams(), rapidcsv::SeparatorParams(),rapidcsv::ConverterParams(true));//解析csv文件 int j=0;//样本计数 for (int i=0;i<doc.GetRowCount();i++){ //每次处理一行 double bill_length_mm = doc.GetCell<double>("bill_length_mm", i);//嘴峰长度 double bill_depth_mm = doc.GetCell<double>("bill_depth_mm", i);//嘴峰深度 double flipper_length_mm = doc.GetCell<double>("flipper_length_mm", i);//脚掌长度 double body_mass_g = doc.GetCell<double>("body_mass_g", i);//体重 std::string sex = doc.GetCell<std::string>("sex", i); //性别 std::string type_name = doc.GetCell<std::string>("species", i); //种族 if ( !std::isnan(bill_length_mm) && !std::isnan(bill_depth_mm) && !std::isnan(flipper_length_mm) && !std::isnan(body_mass_g) && sex!="NA" ){//处理缺失值 data[j].x1 = bill_length_mm;data[j].x2 = bill_depth_mm; data[j].x3 = flipper_length_mm;data[j].x4 = body_mass_g; data[j].x5_0 = sex=="male"?1:0; data[j].x5_1 = sex=="female"?1:0; if (type_name == "Adelie") data[j].label=0; else if (type_name == "Gentoo") data[j].label=1; else data[j].label=2; j++;//剔除缺失值后的样本数目 } } return j; } int main() { DataPoint data[500]; int n = ReadCsv("penguins.csv", data);//从文件读入数据 //将数据拷贝到Mat矩阵中 , 75%训练数据,25%测试数据 int n1=n*3/4, n2=n-n1; Mat train_samples(n1, 6, CV_32F); //训练数据集 Mat train_labels(n1, 3, CV_32F);//训练数据的标签(独热编码) Mat test_samples(n2, 6, CV_32F); //测试数据集 Mat test_labels(n2, 1, CV_32S);//测试数据的标签 int i=0, j=0, k=0; for(i = 0; i<n; i++){ if (i%4==0){//每3个训练数据搭配1个测试数据 test_samples.at<float>(j, 0) = data[i].x1;test_samples.at<float>(j, 1) = data[i].x2; test_samples.at<float>(j, 2) = data[i].x3;test_samples.at<float>(j, 3) = data[i].x4; test_samples.at<float>(j, 4) = data[i].x5_0;test_samples.at<float>(j, 5) = data[i].x5_1; test_labels.at<int>(j, 0) = data[i].label; j++; }else{ train_samples.at<float>(k, 0) = data[i].x1;train_samples.at<float>(k, 1) = data[i].x2; train_samples.at<float>(k, 2) = data[i].x3;train_samples.at<float>(k, 3) = data[i].x4; train_samples.at<float>(k, 4) = data[i].x5_0;train_samples.at<float>(k, 5) = data[i].x5_1; if (data[i].label==0) {//标签转换为独热编码 train_labels.at<float>(k, 0)=1;train_labels.at<float>(k, 1)=0;train_labels.at<float>(k, 2)=0; }else if (data[i].label==1) { train_labels.at<float>(k, 0)=0;train_labels.at<float>(k, 1)=1;train_labels.at<float>(k, 2)=0; }else{ train_labels.at<float>(k, 0)=0;train_labels.at<float>(k, 1)=0;train_labels.at<float>(k, 2)=1; } k++; } } cout<<"n="<<n<<",n1="<<n1<<",n2="<<n2<<endl; Ptr<ANN_MLP> nn = ANN_MLP::create(); //创建神经网络模型 nn->setLayerSizes(vector<int>{6, 10, 3});//输入层6个节点,隐藏层10个节点,输出层3个节点(假设3类企鹅) nn->setActivationFunction(ANN_MLP::SIGMOID_SYM);//激活函数目前只支持Sigmoid nn->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 10000, 1e-5));//设置迭代次数与收敛条件 nn->setTrainMethod(ANN_MLP::RPROP); //弹性反向传播算法 nn->train(train_samples, ROW_SAMPLE, train_labels);//训练模型 Mat predictions; //预测结果 nn->predict(test_samples,predictions);//对测试集进行预测 int correct = 0; //正确分类的次数 for (int i = 0; i < predictions.rows; i++){ Point max_loc; // 找到预测值中的最大索引,即预测的类别 minMaxLoc(predictions.row(i), nullptr, nullptr, nullptr, &max_loc); cout<<"predictions:"<(i, 0)<<endl; if (max_loc.x == test_labels.at<int>(i, 0)) correct++; } double accuracy = (double)correct / predictions.rows; //计算准确率 cout<<"Accuracy: " << accuracy * 100 << "%" << endl; return 0; }

“#include "wall_detection.h" // 全局变量定义 tf2_ros::Buffer* tfBuffer = nullptr; ros::Publisher pointcloud_pub; ros::Publisher lines_pub; ros::Publisher normals_pub; ros::Publisher nearest_point_pub; ros::Publisher tf_points_pub; ros::Publisher min_distance_pub; ros::Publisher nearest_distance_pub; //最近距离 // ros::Publisher left_front_nearest_distance_pub; // 左前侧垂直距离 ros::Publisher right_front_nearest_distance_pub; // 右前侧垂直距离 ros::Publisher left_back_nearest_distance_pub; // 左后侧垂直距离 ros::Publisher right_back_nearest_distance_pub; // 右后侧垂直距离 ros::Publisher foot_points_pub;//垂足 // bool isLeftWall(const DetectedLine& wall) { // 计算墙面中点Y坐标,大于0视为左侧墙面 return (wall.start.y + wall.end.y) / 2.0 > 0; } geometry_msgs::Point left_front_ref, left_back_ref; geometry_msgs::Point right_front_ref, right_back_ref; std::string choose_wall ; bool getPointParameters(ros::NodeHandle& nh) { // 为每个点的每个分量设置默认值 double left_front_default_x = 0.0, left_front_default_y = 0.0, left_front_default_z = 0.0; double left_back_default_x = 0.0, left_back_default_y = 0.0, left_back_default_z = 0.0; double right_front_default_x = 0.0, right_front_default_y = 0.0, right_front_default_z = 0.0; double right_back_default_x = 0.0, right_back_default_y = 0.0, right_back_default_z = 0.0; std::string inital_choose = "all"; // 获取左前点参数 nh.param<double>("left_front_ref_x", left_front_ref.x, left_front_default_x); nh.param<double>("left_front_ref_y", left_front_ref.y, left_front_default_y); nh.param<double>("left_front_ref_z", left_front_ref.z, left_front_default_z); // 获取左后点参数 nh.param<double>("left_back_ref_x", left_back_ref.x, left_back_default_x); nh.param<double>("left_back_ref_y", left_back_ref.y, left_back_default_y); nh.param<double>("left_back_ref_z", left_back_ref.z, left_back_default_z); // 获取右前点参数 nh.param<double>("right_front_ref_x", right_front_ref.x, right_front_default_x); nh.param<double>("right_front_ref_y", right_front_ref.y, right_front_default_y); nh.param<double>("right_front_ref_z", right_front_ref.z, right_front_default_z); // 获取右后点参数 nh.param<double>("right_back_ref_x", right_back_ref.x, right_back_default_x); nh.param<double>("right_back_ref_y", right_back_ref.y, right_back_default_y); nh.param<double>("right_back_ref_z", right_back_ref.z, right_back_default_z); nh.param<std::string>("choose_wall",choose_wall, "inital_choose"); // 打印获取的值 ROS_INFO("Left Front Ref: (%.2f, %.2f, %.2f)", left_front_ref.x, left_front_ref.y, left_front_ref.z); ROS_INFO("Left Back Ref: (%.2f, %.2f, %.2f)", left_back_ref.x, left_back_ref.y, left_back_ref.z); ROS_INFO("Right Front Ref: (%.2f, %.2f, %.2f)", right_front_ref.x, right_front_ref.y, right_front_ref.z); ROS_INFO("Right Back Ref: (%.2f, %.2f, %.2f)", right_back_ref.x, right_back_ref.y, right_back_ref.z); ROS_INFO("Choose_wall_type: %s", choose_wall.c_str()); return true; } void setupStaticTFs() { static tf2_ros::StaticTransformBroadcaster static_broadcaster; // 位于激光雷达左前方的tf坐标 geometry_msgs::TransformStamped left_tf; //left_tf.header.stamp = ros::Time::now(); left_tf.header.stamp = ros::Time(0); left_tf.header.frame_id = "base_footprint"; left_tf.child_frame_id = "laser_left_front"; left_tf.transform.translation.x = left_front_ref.x; left_tf.transform.translation.y = left_front_ref.y; left_tf.transform.translation.z = left_front_ref.z; left_tf.transform.rotation.x = 0.0; left_tf.transform.rotation.y = 0.0; left_tf.transform.rotation.z = 0.0; left_tf.transform.rotation.w = 1.0; // 位于激光雷达右前方的tf坐标 geometry_msgs::TransformStamped right_tf; //right_tf.header.stamp = ros::Time::now(); right_tf.header.stamp = ros::Time(0); right_tf.header.frame_id = "base_footprint"; right_tf.child_frame_id = "laser_right_front"; right_tf.transform.translation.x = right_front_ref.x; right_tf.transform.translation.y = right_front_ref.y; right_tf.transform.translation.z = right_front_ref.z; right_tf.transform.rotation.x = 0.0; right_tf.transform.rotation.y = 0.0; right_tf.transform.rotation.z = 0.0; right_tf.transform.rotation.w = 1.0; //左后方TF坐标 geometry_msgs::TransformStamped left_back_tf; //left_back_tf.header.stamp = ros::Time::now(); left_back_tf.header.stamp = ros::Time(0); left_back_tf.header.frame_id = "base_footprint"; left_back_tf.child_frame_id = "laser_left_back"; left_back_tf.transform.translation.x = left_back_ref.x; left_back_tf.transform.translation.y = left_back_ref.y; left_back_tf.transform.translation.z = left_back_ref.z; left_back_tf.transform.rotation.x = 0.0; left_back_tf.transform.rotation.y = 0.0; left_back_tf.transform.rotation.z = 0.0; left_back_tf.transform.rotation.w = 1.0; // 右后方TF坐标 geometry_msgs::TransformStamped right_back_tf; //right_back_tf.header.stamp = ros::Time::now(); right_back_tf.header.stamp = ros::Time(0); right_back_tf.header.frame_id = "base_footprint"; right_back_tf.child_frame_id = "laser_right_back"; right_back_tf.transform.translation.x = right_back_ref.x; right_back_tf.transform.translation.y = right_back_ref.y; right_back_tf.transform.translation.z = right_back_ref.z; right_back_tf.transform.rotation.x = 0.0; right_back_tf.transform.rotation.y = 0.0; right_back_tf.transform.rotation.z = 0.0; right_back_tf.transform.rotation.w = 1.0; static_broadcaster.sendTransform(left_tf); static_broadcaster.sendTransform(right_tf); static_broadcaster.sendTransform(left_back_tf); static_broadcaster.sendTransform(right_back_tf); } double pointToLineDistance(const geometry_msgs::Point& point, const geometry_msgs::Point& line_start, const geometry_msgs::Point& line_end) { Eigen::Vector3f pt(point.x, point.y, point.z); Eigen::Vector3f line_vec(line_end.x - line_start.x, line_end.y - line_start.y, line_end.z - line_start.z); Eigen::Vector3f pt_vec(pt.x() - line_start.x, pt.y() - line_start.y, pt.z() - line_start.z); double line_length = line_vec.norm(); if (line_length < 1e-6) { return pt_vec.norm(); } Eigen::Vector3f normalized_line = line_vec / line_length; double projection = pt_vec.dot(normalized_line); // 限制投影在直线范围内 projection = std::max(0.0, std::min(line_length, projection)); Eigen::Vector3f closest_point = Eigen::Vector3f(line_start.x, line_start.y, line_start.z) + projection * normalized_line; return (pt - closest_point).norm(); } // 计算点到直线的垂足点 geometry_msgs::Point pointToLineProjection(const geometry_msgs::Point& point, const geometry_msgs::Point& line_start, const geometry_msgs::Point& line_end) { Eigen::Vector3f pt(point.x, point.y, point.z); Eigen::Vector3f line_vec(line_end.x - line_start.x, line_end.y - line_start.y, line_end.z - line_start.z); Eigen::Vector3f pt_vec(pt.x() - line_start.x, pt.y() - line_start.y, pt.z() - line_start.z); double line_length = line_vec.norm(); if (line_length < 1e-6) { return line_start; // 如果直线长度为零,返回起点 } Eigen::Vector3f normalized_line = line_vec / line_length; double projection = pt_vec.dot(normalized_line); // 限制投影在直线范围内 projection = std::max(0.0, std::min(line_length, projection)); Eigen::Vector3f closest_point = Eigen::Vector3f(line_start.x, line_start.y, line_start.z) + projection * normalized_line; geometry_msgs::Point foot_point; foot_point.x = closest_point.x(); foot_point.y = closest_point.y(); foot_point.z = closest_point.z(); return foot_point; } void publishDetectedLines(const std::vector<DetectedLine>& lines, const std::string& frame_id) { visualization_msgs::Marker line_marker; line_marker.header.frame_id = frame_id; line_marker.header.stamp = ros::Time::now(); line_marker.ns = "detected_line"; line_marker.id = 0; line_marker.type = visualization_msgs::Marker::LINE_LIST; line_marker.pose.orientation.w = 1.0; line_marker.scale.x = 0.15; line_marker.color.r = 0.0; line_marker.color.g = 0.0; line_marker.color.b = 1.0; line_marker.color.a = 1.0; for (const auto& line : lines) { geometry_msgs::Point p1, p2; p1.x = line.start.x; p1.y = line.start.y; p1.z = line.start.z; p2.x = line.end.x; p2.y = line.end.y; p2.z = line.end.z; line_marker.points.push_back(p1); line_marker.points.push_back(p2); } lines_pub.publish(line_marker); visualization_msgs::MarkerArray normal_markers; int id = 0; for (const auto& line : lines) { visualization_msgs::Marker normal_marker; normal_marker.header.frame_id = frame_id; normal_marker.header.stamp = ros::Time::now(); normal_marker.ns = "normals"; normal_marker.id = id++; normal_marker.type = visualization_msgs::Marker::ARROW; normal_marker.action = visualization_msgs::Marker::ADD; normal_marker.pose.orientation.w = 1.0; normal_marker.scale.x = 0.02; normal_marker.scale.y = 0.04; normal_marker.scale.z = 0.0; normal_marker.color.r = 1.0; normal_marker.color.g = 0.0; normal_marker.color.b = 0.0; normal_marker.color.a = 1.0; geometry_msgs::Point mid_point; mid_point.x = (line.start.x + line.end.x) / 2.0; mid_point.y = (line.start.y + line.end.y) / 2.0; mid_point.z = (line.start.z + line.end.z) / 2.0; geometry_msgs::Point normal_end; normal_end.x = mid_point.x + line.normal.normal_x * 0.5; normal_end.y = mid_point.y + line.normal.normal_y * 0.5; normal_end.z = mid_point.z + line.normal.normal_z * 0.5; normal_marker.points.push_back(mid_point); normal_marker.points.push_back(normal_end); normal_markers.markers.push_back(normal_marker); } normals_pub.publish(normal_markers); } void publishNearestPointMarker(const geometry_msgs::Point& point,float distance,const std::string& frame_id, const std::string& ref_name) { visualization_msgs::Marker marker; marker.header.frame_id = frame_id; marker.header.stamp = ros::Time::now(); marker.ns = "nearest_point" + ref_name; // marker.id = 0; marker.type = visualization_msgs::Marker::SPHERE; marker.action = visualization_msgs::Marker::ADD; marker.pose.position = point; marker.pose.orientation.w = 1.0; marker.scale.x = 0.15; marker.scale.y = 0.15; marker.scale.z = 0.15; marker.color.r = 1.0; marker.color.g = 0.0; marker.color.b = 0.0; marker.color.a = 1.0; marker.lifetime = ros::Duration(0.1); nearest_point_pub.publish(marker); //std_msgs::Float64 dist; //dist.data =(point.y < 0 ? -1.0 : 1.0) *(std::fabs(point.y) - 0.12); //dist.data = std::fabs(point.y); //nearest_distance_pub.publish(dist); //最近距离 std_msgs::Float64 dist_msg; if (ref_name == "left_front") { dist_msg.data = distance; left_front_nearest_distance_pub.publish(dist_msg); } else if (ref_name == "left_back") { dist_msg.data = distance; left_back_nearest_distance_pub.publish(dist_msg); } else if (ref_name == "right_front") { dist_msg.data = distance; right_front_nearest_distance_pub.publish(dist_msg); } else { dist_msg.data = distance; right_back_nearest_distance_pub.publish(dist_msg); } // } /***************************************************************/ void publishFootPointMarker(const geometry_msgs::Point& left_front_foot, //垂足标记 const geometry_msgs::Point& left_back_foot, //垂足标记 const geometry_msgs::Point& right_front_foot, const geometry_msgs::Point& right_back_foot, const std::string& frame_id) { visualization_msgs::Marker marker; marker.header.frame_id = frame_id; marker.header.stamp = ros::Time::now(); marker.ns = "foot_points"; marker.id = 0; marker.type = visualization_msgs::Marker::POINTS; marker.action = visualization_msgs::Marker::ADD; marker.scale.x = 0.1; // 点的大小 marker.scale.y = 0.1; marker.color.a = 1.0; // 不透明度 // 添加左侧垂足点 - 蓝色 marker.points.push_back(left_front_foot); std_msgs::ColorRGBA color; color.r = 0.0; color.g = 0.0; color.b = 1.0; color.a = 1.0; marker.colors.push_back(color); // 添加右侧垂足点 - 绿色 marker.points.push_back(right_front_foot); color.r = 0.0; color.g = 1.0; color.b = 0.0; color.a = 1.0; marker.colors.push_back(color); // 添加左侧垂足点 - 蓝色 marker.points.push_back(left_back_foot); color.r = 0.0; color.g = 1.0; color.b = 1.0; color.a = 1.0; marker.colors.push_back(color); // 添加右侧垂足点 - 绿色 marker.points.push_back(right_back_foot); color.r = 1.0; color.g = 1.0; color.b = 0.0; color.a = 1.0; marker.colors.push_back(color); foot_points_pub.publish(marker); } /*******************************************************************/ void publishTFPoints(const geometry_msgs::Point& left_front_point, const geometry_msgs::Point& left_back_point, const geometry_msgs::Point& right_front_point, const geometry_msgs::Point& right_back_point, const std::string& frame_id) { visualization_msgs::Marker marker; marker.header.frame_id = frame_id; marker.header.stamp = ros::Time::now(); marker.ns = "tf_point"; marker.id = 0; marker.type = visualization_msgs::Marker::POINTS; marker.action = visualization_msgs::Marker::ADD; marker.scale.x = 0.15; marker.scale.y = 0.15; marker.color.a = 1.0; // 左侧点 - 蓝色 geometry_msgs::Point p; p = left_front_point; marker.points.push_back(p); std_msgs::ColorRGBA c; c.r = 0.0; c.g = 0.0; c.b = 1.0; c.a = 1.0; marker.colors.push_back(c); // 右侧点 - 绿色 p = right_front_point; marker.points.push_back(p); c.r = 0.0; c.g = 1.0; c.b = 0.0; c.a = 1.0; marker.colors.push_back(c); // 左侧点 - 蓝色 p = left_back_point; marker.points.push_back(p); c.r = 0.0; c.g = 1.0; c.b = 1.0; c.a = 1.0; marker.colors.push_back(c); // 右侧点 - 绿色 p = right_back_point; marker.points.push_back(p); c.r = 1.0; c.g = 1.0; c.b = 0.0; c.a = 1.0; marker.colors.push_back(c); tf_points_pub.publish(marker); } void publishDistanceInfo(const std::string& frame_id, double left_front_dist, double left_back_dist, double right_front_dist, double right_back_dist, const geometry_msgs::Point& wall_point) { visualization_msgs::Marker marker; marker.header.frame_id = frame_id; marker.header.stamp = ros::Time::now(); marker.ns = "distance_info"; marker.id = 0; marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING; marker.action = visualization_msgs::Marker::ADD; marker.pose.position = wall_point; marker.pose.position.z += 0.5; // 在墙上点上方显示 marker.pose.orientation.w = 1.0; marker.scale.z = 0.2; // 文本大小 marker.color.r = 1.0; marker.color.g = 1.0; marker.color.b = 0.0; marker.color.a = 1.0; std::stringstream ss; ss << std::fixed << std::setprecision(2); ss << "Left_front_tf: " << left_front_dist << "m\n"; ss << "Left_back_tf: " << left_back_dist << "m\n"; ss << "Right_front_tf: " << right_front_dist << "m\n"; ss << "Right_back_tf: " << right_back_dist << "m\n"; if (left_front_dist < right_front_dist && left_back_dist < right_back_dist ) { ss << "Left is closer"; } else if (right_front_dist < left_front_dist && right_back_dist < left_back_dist ) { ss << "Right is closer"; } else { ss << "Equal distance"; } marker.text = ss.str(); min_distance_pub.publish(marker); } float min_four(float a ,float b , float c , float d ) { return std::min({a, b, c, d}); } void LidarCallback(const sensor_msgs::LaserScan::ConstPtr& msg) { std::unordered_map<int, PointData> point_data_map; PointCloudT::Ptr cloud(new PointCloudT); cloud->header.frame_id = msg->header.frame_id; cloud->height = 1; cloud->is_dense = false; float min_distance = std::numeric_limits<float>::max(); int min_index = -1; int point_count = 0; const float min_angle1 = 30 * M_PI/180.0; const float max_angle1 = 150* M_PI/180.0; const float min_angle2 = -150 * M_PI/180.0; const float max_angle2 = -30 * M_PI/180.0; // 为参考点初始化最小距离 float left_front_min_distance = std::numeric_limits<float>::max(); int left_front_min_index = -1; geometry_msgs::Point left_front_nearest_point; float left_back_min_distance = std::numeric_limits<float>::max(); int left_back_min_index = -1; geometry_msgs::Point left_back_nearest_point; // 为参考点初始化最小距离 float right_front_min_distance = std::numeric_limits<float>::max(); int right_front_min_index = -1; geometry_msgs::Point right_front_nearest_point; float right_back_min_distance = std::numeric_limits<float>::max(); int right_back_min_index = -1; geometry_msgs::Point right_back_nearest_point; // 寻找最近点 for (size_t i = 0; i < msg->ranges.size(); ++i) { const float range = msg->ranges[i]; if (std::isnan(range)) continue; if (range < msg->range_min || range > msg->range_max) continue; const float angle = msg -> angle_min + i * msg -> angle_increment; //创建屏蔽条件检测 bool in_blocked_zone = true; float normalized_angle = angle; const float x = range * cos(angle); const float y = range * sin(angle); if (choose_wall == "left") { // 左侧 if (angle >= min_angle1 && angle <= max_angle1) { // if ( x > left_front_ref.x || x < left_back_ref.x) // { // in_blocked_zone= false; // } in_blocked_zone= false; } } else if (choose_wall == "right") { // 右侧 if (angle >= min_angle2 && angle <= max_angle2) { // if ( x > right_front_ref.x || x < right_back_ref.x) // { // in_blocked_zone= false; // } in_blocked_zone= false; } } else { if (angle >= min_angle1 && angle <= max_angle1) { // if ( x > left_front_ref.x || x < left_back_ref.x) // { // in_blocked_zone= false; // } in_blocked_zone= false; } if (angle >= min_angle2 && angle <= max_angle2) { // if ( x > right_front_ref.x || x < right_back_ref.x) // { // in_blocked_zone= false; // } in_blocked_zone= false; } } if (in_blocked_zone) continue; if (range < min_distance) { min_distance = range; min_index = i; } PointT point; point.x = range * cos(angle); point.y = range * sin(angle); point.z = 0.0; point.r = 0; point.g = 255; point.b = 0; PointData data; data.original_index = i; data.is_line_point = false; data.is_nearest = (i == min_index); point_data_map[point_count] = data; cloud->points.push_back(point); point_count++; } cloud->width = point_count; // 如果点云为空,直接返回 if (cloud->empty()) { ROS_WARN_THROTTLE(1.0, "No valid points found"); return; } std::vector<DetectedLine> detected_lines; pcl::search::KdTree::Ptr tree(new pcl::search::KdTree); tree->setInputCloud(cloud); // 2. 执行欧几里得聚类 - 确保连续性 std::vector cluster_indices; pcl::EuclideanClusterExtraction ec; ec.setClusterTolerance(0.15); // 点间最大距离阈值(米) ec.setMinClusterSize(30); // 最小聚类点数 ec.setMaxClusterSize(10000); // 最大聚类点数 ec.setSearchMethod(tree); ec.setInputCloud(cloud); ec.extract(cluster_indices); ROS_INFO_THROTTLE(1.0, "Detected %zu point cloud clusters", cluster_indices.size()); std::vector<std::vector<uint8_t>> colors = { {255, 0, 0}, // 红 {0, 255, 0}, // 绿 {0, 0, 255}, // 蓝 {255, 255, 0}, // 黄 {0, 255, 255}, // 青 {255, 0, 255} // 紫 }; // 初始化点云颜色 for (auto& point : cloud->points) { point.r = 0; point.g = 255; point.b = 0; } // 3. 对每个聚类进行直线检测 for (size_t i = 0; i < cluster_indices.size(); i++) { const auto& cluster = cluster_indices[i]; // 创建当前聚类的点云 PointCloudT::Ptr cluster_cloud(new PointCloudT); for (const auto& idx : cluster.indices) { cluster_cloud->push_back((*cloud)[idx]); } // 为当前聚类的点着色 const auto& color = colors[i % colors.size()]; for (const auto& idx : cluster.indices) { cloud->points[idx].r = color[0]; cloud->points[idx].g = color[1]; cloud->points[idx].b = color[2]; } // 跳过点数过少的聚类 if (cluster_cloud->size() < 10) continue; pcl::SACSegmentation seg; pcl::PointIndices::Ptr inliers(new pcl::PointIndices); pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients); seg.setOptimizeCoefficients(true); seg.setModelType(pcl::SACMODEL_LINE); seg.setMethodType(pcl::SAC_RANSAC); seg.setMaxIterations(1000); seg.setDistanceThreshold(0.05); // 点到直线的最大距离阈值 seg.setInputCloud(cluster_cloud); seg.segment(*inliers, *coefficients); if (inliers->indices.size() < 10) continue; DetectedLine line; float min_proj = std::numeric_limits<float>::max(); float max_proj = std::numeric_limits<float>::lowest(); Eigen::Vector3f direction(coefficients->values[3], coefficients->values[4], 0.0f); direction.normalize(); // 计算直线的起点和终点 for (const auto& idx : inliers->indices) { Eigen::Vector3f pt( cluster_cloud->points[idx].x, cluster_cloud->points[idx].y, 0.0f ); float proj = pt.dot(direction); if (proj < min_proj) { min_proj = proj; line.start.x = pt.x(); line.start.y = pt.y(); line.start.z = 0.0f; } if (proj > max_proj) { max_proj = proj; line.end.x = pt.x(); line.end.y = pt.y(); line.end.z = 0.0f; } } // 计算法线方向 line.normal.normal_x = -direction.y(); line.normal.normal_y = direction.x(); line.normal.normal_z = 0.0f; line.direction = direction; detected_lines.push_back(line); // 标记直线点 for (const auto& inlier_idx : inliers->indices) { if (inlier_idx >= 0 && inlier_idx < cluster.indices.size()) { int original_idx = cluster.indices[inlier_idx]; if (original_idx >= 0 && original_idx < cloud->size()) { point_data_map[original_idx].is_line_point = true; } } } } // 更新点云颜色 for (int i = 0; i < cloud->size(); i++) { if (point_data_map[i].is_line_point) { cloud->points[i].r = 255; cloud->points[i].g = 255; cloud->points[i].b = 0; } } sensor_msgs::PointCloud2 cloud_msg; pcl::toROSMsg(*cloud, cloud_msg); cloud_msg.header = msg->header; std::vector<DetectedLine> transformed_lines; geometry_msgs::Point left_front_tf_point_map ,left_back_tf_point_map ; geometry_msgs::Point right_front_tf_point_map , right_back_tf_point_map ; bool left_front_tf_valid = false , left_back_tf_valid = false; bool right_front_tf_valid = false , right_back_tf_valid = false; if (tfBuffer) { try { if (!tfBuffer->canTransform("base_footprint", cloud_msg.header.frame_id, cloud_msg.header.stamp, ros::Duration(0.1))) { ROS_WARN_THROTTLE(1.0, "TF transform not available"); return; } // 转换点云 sensor_msgs::PointCloud2 transformed_cloud; tfBuffer->transform(cloud_msg, transformed_cloud, "base_footprint"); transformed_cloud.header.stamp = ros::Time::now(); transformed_cloud.header.frame_id = "base_footprint"; pointcloud_pub.publish(transformed_cloud); // 转换检测到的直线 if (!detected_lines.empty()) { for (auto& line : detected_lines) { geometry_msgs::PointStamped laser_start, map_start; laser_start.header = msg->header; laser_start.point.x = line.start.x; laser_start.point.y = line.start.y; laser_start.point.z = 0.0f; tfBuffer->transform(laser_start, map_start, "base_footprint"); geometry_msgs::PointStamped laser_end, map_end; laser_end.header = msg->header; laser_end.point.x = line.end.x; laser_end.point.y = line.end.y; laser_end.point.z = 0.0f; tfBuffer->transform(laser_end, map_end, "base_footprint"); geometry_msgs::Vector3Stamped laser_normal, map_normal; laser_normal.header = msg->header; laser_normal.vector.x = line.normal.normal_x; laser_normal.vector.y = line.normal.normal_y; laser_normal.vector.z = 0.0f; tfBuffer->transform(laser_normal, map_normal, "base_footprint"); DetectedLine transformed_line; transformed_line.start.x = map_start.point.x; transformed_line.start.y = map_start.point.y; transformed_line.start.z = map_start.point.z; transformed_line.end.x = map_end.point.x; transformed_line.end.y = map_end.point.y; transformed_line.end.z = map_end.point.z; transformed_line.normal.normal_x = map_normal.vector.x; transformed_line.normal.normal_y = map_normal.vector.y; transformed_line.normal.normal_z = map_normal.vector.z; transformed_lines.push_back(transformed_line); } publishDetectedLines(transformed_lines, "base_footprint"); } // 获取TF参考点在base_footprint中的位置 try { geometry_msgs::PointStamped left_front_tf_laser, left_front_tf_map; left_front_tf_laser.header.frame_id = "laser_left_front"; left_front_tf_laser.header.stamp = ros::Time(0); left_front_tf_laser.point.x = left_front_ref.x; left_front_tf_laser.point.y = left_front_ref.y; left_front_tf_laser.point.z = left_front_ref.z; tfBuffer->transform(left_front_tf_laser, left_front_tf_map, "base_footprint"); left_front_tf_point_map = left_front_tf_map.point; left_front_tf_valid = true; geometry_msgs::PointStamped left_back_tf_laser, left_back_tf_map; left_back_tf_laser.header.frame_id = "laser_left_back"; left_back_tf_laser.header.stamp = ros::Time(0); left_back_tf_laser.point.x = left_back_ref.x; left_back_tf_laser.point.y = left_back_ref.y; left_back_tf_laser.point.z = left_back_ref.z; tfBuffer->transform(left_back_tf_laser, left_back_tf_map, "base_footprint"); left_back_tf_point_map = left_back_tf_map.point; left_back_tf_valid = true; geometry_msgs::PointStamped right_front_tf_laser, right_front_tf_map; right_front_tf_laser.header.frame_id = "laser_right_front"; right_front_tf_laser.header.stamp = ros::Time(0); right_front_tf_laser.point.x = right_front_ref.x; right_front_tf_laser.point.y = right_front_ref.y; right_front_tf_laser.point.z = right_front_ref.z; tfBuffer->transform(right_front_tf_laser, right_front_tf_map, "base_footprint"); right_front_tf_point_map = right_front_tf_map.point; right_front_tf_valid = true; geometry_msgs::PointStamped right_back_tf_laser, right_back_tf_map; right_back_tf_laser.header.frame_id = "laser_right_back"; right_back_tf_laser.header.stamp = ros::Time(0); right_back_tf_laser.point.x = right_back_ref.x; right_back_tf_laser.point.y = right_back_ref.y; right_back_tf_laser.point.z = right_back_ref.z; tfBuffer->transform(right_back_tf_laser, right_back_tf_map, "base_footprint"); right_back_tf_point_map = right_back_tf_map.point; right_back_tf_valid = true; publishTFPoints(left_front_tf_point_map, left_back_tf_point_map, right_front_tf_point_map, right_back_tf_point_map, "base_footprint"); } catch (tf2::TransformException& ex) { ROS_WARN_THROTTLE(1.0, "TF point transform error: %s", ex.what()); } } catch (tf2::TransformException& ex) { ROS_WARN_THROTTLE(1.0, "TF point transform error: %s", ex.what()); } } if ( ! transformed_lines.empty() && left_front_tf_valid && left_back_tf_valid && right_front_tf_valid && right_back_tf_valid) { std::vector<DetectedLine>left_walls; std::vector<DetectedLine>right_walls; for (const auto& wall : transformed_lines) { if (isLeftWall(wall)) { left_walls.push_back(wall); } else { right_walls.push_back(wall); } } double left_front_min_dist = std::numeric_limits<double>::max(); double left_back_min_dist = std::numeric_limits<double>::max(); geometry_msgs::Point left_front_foot , left_back_foot; geometry_msgs::Point left_front_wall_point, left_back_wall_point; for (const auto& wall : left_walls) { geometry_msgs::Point start_point, end_point; start_point.x = wall.start.x; start_point.y = wall.start.y; start_point.z = wall.start.z; end_point.x = wall.end.x; end_point.y = wall.end.y; end_point.z = wall.end.z; double dist_front = pointToLineDistance( left_front_tf_point_map, start_point, end_point); // 计算垂足点 geometry_msgs::Point foot_front = pointToLineProjection( left_front_tf_point_map, start_point, end_point ); if (dist_front < left_front_min_dist) { left_front_min_dist = dist_front; left_front_foot = foot_front; left_front_wall_point = foot_front; } double dist_back = pointToLineDistance( left_back_tf_point_map, start_point, end_point); // 计算垂足点 geometry_msgs::Point foot_back = pointToLineProjection( left_back_tf_point_map, start_point, end_point ); if (dist_back < left_back_min_dist) { left_back_min_dist = dist_back; left_back_foot = foot_back; left_back_wall_point = foot_back; } } //右墙 double right_front_min_dist = std::numeric_limits<double>::max(); double right_back_min_dist = std::numeric_limits<double>::max(); geometry_msgs::Point right_front_foot, right_back_foot; geometry_msgs::Point right_front_wall_point, right_back_wall_point; for (const auto& wall : right_walls) { geometry_msgs::Point start_point, end_point; start_point.x = wall.start.x; start_point.y = wall.start.y; start_point.z = wall.start.z; end_point.x = wall.end.x; end_point.y = wall.end.y; end_point.z = wall.end.z; // 计算右前参考点 double dist_front = pointToLineDistance( right_front_tf_point_map, start_point, end_point ); // 计算垂足点 geometry_msgs::Point foot_front = pointToLineProjection( right_front_tf_point_map, start_point, end_point ); if (dist_front < right_front_min_dist) { right_front_min_dist = dist_front; right_front_foot = foot_front; right_front_wall_point = foot_front; } // 计算右后参考点 double dist_back = pointToLineDistance( right_back_tf_point_map, start_point, end_point ); // 计算垂足点 geometry_msgs::Point foot_back = pointToLineProjection( right_back_tf_point_map, start_point, end_point ); if (dist_back < right_back_min_dist) { right_back_min_dist = dist_back; right_back_foot = foot_back; right_back_wall_point = foot_back; } } std_msgs::Float64 left_front_distance_msg, left_back_distance_msg , right_front_distance_msg , right_back_distance_msg; // 左前距离 double left_front_vertical_dist = (left_front_min_dist == std::numeric_limits<double>::max()) ? 10.0 : left_front_min_dist; left_front_distance_msg.data = left_front_vertical_dist; //left_front_nearest_distance_pub.publish(left_front_distance_msg); // 左后距离 double left_back_vertical_dist = (left_back_min_dist == std::numeric_limits<double>::max()) ? 10.0 : left_back_min_dist; left_back_distance_msg.data = left_back_vertical_dist; //left_back_nearest_distance_pub.publish(left_back_distance_msg); // 右前距离 double right_front_vertical_dist = (right_front_min_dist == std::numeric_limits<double>::max()) ? 10.0 : right_front_min_dist; right_front_distance_msg.data = right_front_vertical_dist; //right_front_nearest_distance_pub.publish(right_front_distance_msg); // 右后距离 double right_back_vertical_dist = (right_back_min_dist == std::numeric_limits<double>::max()) ? 10.0 : right_back_min_dist; right_back_distance_msg.data = right_back_vertical_dist; //right_back_nearest_distance_pub.publish(right_back_distance_msg); // 发布垂足点 publishFootPointMarker(left_front_foot, left_back_foot, right_front_foot, right_back_foot, "base_footprint"); // 发布距离信息 geometry_msgs::Point wall_mid_point; wall_mid_point.x = (left_front_wall_point.x + right_front_wall_point.x) / 2; wall_mid_point.y = (left_front_wall_point.y + right_front_wall_point.y) / 2; wall_mid_point.z = 0; float dist_min = min_four(left_front_vertical_dist,left_back_vertical_dist,right_front_vertical_dist,right_back_vertical_dist); if ( dist_min == left_front_vertical_dist ) { nearest_distance_pub.publish(left_front_distance_msg); } else if ( dist_min == left_back_vertical_dist ) { nearest_distance_pub.publish(left_back_distance_msg); } else if ( dist_min == right_front_vertical_dist ) { nearest_distance_pub.publish(right_front_distance_msg); } else { nearest_distance_pub.publish(right_back_distance_msg); } publishDistanceInfo("base_footprint", left_front_min_distance, left_back_min_distance, right_front_min_distance, right_back_min_distance, wall_mid_point); ROS_INFO_THROTTLE(1.0, "Left Front TF to wall: %.3f m, Left Back TF to wall: %.3f m , Right Front TF to wall: %.3f m, Right Bcak TF to wall: %.3f m", left_front_vertical_dist , left_back_vertical_dist ,right_front_vertical_dist ,right_back_vertical_dist ); } }”修改成你给我的样子,rviz观察到的四个tf坐标还是(0,0,0)

最新推荐

recommend-type

2014年直流电压电流采样仪生产方案:电路板、BOM单、STM单片机程序及应用 核心版

2014年设计的一款直流电压电流采样仪的整套产品生产方案。该产品已量产1000余套,适用于电力、电子、通信等领域。文中涵盖了硬件和软件两大部分的内容。硬件方面,包括电路板设计、BOM单、外围器件清单以及外壳设计;软件方面,则涉及STM单片机程序和配套的上位机电脑软件。该采样仪的最大测量范围为1000V/100A,具备高精度、高稳定性的特点,能记录并存储8组电压电流数据,并带有触发模式用于实时监测和故障诊断。 适合人群:从事电力、电子、通信领域的工程师和技术人员,尤其是对直流电压电流采样仪有需求的研发人员。 使用场景及目标:①帮助工程师和技术人员了解直流电压电流采样仪的整体设计方案;②提供详细的硬件和软件资料,便于实际生产和应用;③适用于需要高精度、高稳定性的电压电流测量场合。 其他说明:该产品已经成功量产并获得市场好评,文中提供的方案对于相关领域的项目开发具有重要参考价值。
recommend-type

Python程序TXLWizard生成TXL文件及转换工具介绍

### 知识点详细说明: #### 1. 图形旋转与TXL向导 图形旋转是图形学领域的一个基本操作,用于改变图形的方向。在本上下文中,TXL向导(TXLWizard)是由Esteban Marin编写的Python程序,它实现了特定的图形旋转功能,主要用于电子束光刻掩模的生成。光刻掩模是半导体制造过程中非常关键的一个环节,它确定了在硅片上沉积材料的精确位置。TXL向导通过生成特定格式的TXL文件来辅助这一过程。 #### 2. TXL文件格式与用途 TXL文件格式是一种基于文本的文件格式,它设计得易于使用,并且可以通过各种脚本语言如Python和Matlab生成。这种格式通常用于电子束光刻中,因为它的文本形式使得它可以通过编程快速创建复杂的掩模设计。TXL文件格式支持引用对象和复制对象数组(如SREF和AREF),这些特性可以用于优化电子束光刻设备的性能。 #### 3. TXLWizard的特性与优势 - **结构化的Python脚本:** TXLWizard 使用结构良好的脚本来创建遮罩,这有助于开发者创建清晰、易于维护的代码。 - **灵活的Python脚本:** 作为Python程序,TXLWizard 可以利用Python语言的灵活性和强大的库集合来编写复杂的掩模生成逻辑。 - **可读性和可重用性:** 生成的掩码代码易于阅读,开发者可以轻松地重用和修改以适应不同的需求。 - **自动标签生成:** TXLWizard 还包括自动为图形对象生成标签的功能,这在管理复杂图形时非常有用。 #### 4. TXL转换器的功能 - **查看.TXL文件:** TXL转换器(TXLConverter)允许用户将TXL文件转换成HTML或SVG格式,这样用户就可以使用任何现代浏览器或矢量图形应用程序来查看文件。 - **缩放和平移:** 转换后的文件支持缩放和平移功能,这使得用户在图形界面中更容易查看细节和整体结构。 - **快速转换:** TXL转换器还提供快速的文件转换功能,以实现有效的蒙版开发工作流程。 #### 5. 应用场景与技术参考 TXLWizard的应用场景主要集中在电子束光刻技术中,特别是用于设计和制作半导体器件时所需的掩模。TXLWizard作为一个向导,不仅提供了生成TXL文件的基础框架,还提供了一种方式来优化掩模设计,提高光刻过程的效率和精度。对于需要进行光刻掩模设计的工程师和研究人员来说,TXLWizard提供了一种有效的方法来实现他们的设计目标。 #### 6. 系统开源特性 标签“系统开源”表明TXLWizard遵循开放源代码的原则,这意味着源代码对所有人开放,允许用户自由地查看、修改和分发软件。开源项目通常拥有活跃的社区,社区成员可以合作改进软件,添加新功能,或帮助解决遇到的问题。这种开放性促进了技术创新,并允许用户根据自己的需求定制软件。 #### 7. 压缩包子文件的文件名称列表 文件名称列表中的“txlwizard-master”可能指的是TXLWizard项目的主版本库或主分支。这个名称表明了这是项目源代码的中心点,其他开发者会从这个主分支拉取代码进行合作开发或部署。以“-master”结尾通常是版本控制系统中表示主要开发线路的常见约定,例如Git中的master(现在更常被称为main)分支。 通过这些知识点的详细解释,我们可以看到TXLWizard不仅是一个用于生成TXL文件的工具,它还整合了一系列的功能,使得电子束光刻掩模的设计工作更为高效和直观。同时,作为一个开源项目,它能够借助社区的力量不断进步,为用户带来更多的便利和创新。
recommend-type

【创新图生成:扣子平台的技术前沿与创新思维】:引领图像生成技术的新潮流

# 1. 扣子平台的图像生成技术概述 在当今数字化时代,图像生成技术正成为推动技术创新和社会变革的关键力量。扣子平台正是这一技术革新的代表。本章将对扣子平台的图像生成技术进行一个全面概述,探究它如何将理论技术转化为实际应用,并带来显著的社会影响。 扣子平台运用了先进的图像生成技术,将现实世界和数字空间无缝融合,打造了沉浸式的视觉体验。其技术的核心是通过高度复杂的算法模型,快速生成高质
recommend-type

海康威视机器视觉工程师考核

<think>好的,我现在需要帮助用户了解海康威视机器视觉工程师的考核内容和要求。根据用户提供的引用资料,特别是引用[1]和[2],里面提到了考核素材包分为初级和中级,涵盖理论、算法、应用案例等。首先,我要整理这些信息,确保结构清晰,符合用户要求的格式。 接下来,我需要确认素材包的具体内容,比如初级和中级的不同点。引用[2]提到初级包含基础理论、算法实现和实际案例,中级则增加复杂算法和项目分析。这部分需要分点说明,方便用户理解层次。 另外,用户可能想知道如何准备考核,比如下载素材、学习顺序、模拟考核等,引用[2]中有使用说明和注意事项,这部分也要涵盖进去。同时要注意提醒用户考核窗口已关闭,
recommend-type

Linux环境下Docker Hub公共容器映像检测工具集

在给出的知识点中,我们需要详细解释有关Docker Hub、公共容器映像、容器编排器以及如何与这些工具交互的详细信息。同时,我们会涵盖Linux系统下的相关操作和工具使用,以及如何在ECS和Kubernetes等容器编排工具中运用这些检测工具。 ### Docker Hub 和公共容器映像 Docker Hub是Docker公司提供的一项服务,它允许用户存储、管理以及分享Docker镜像。Docker镜像可以视为应用程序或服务的“快照”,包含了运行特定软件所需的所有必要文件和配置。公共容器映像指的是那些被标记为公开可见的Docker镜像,任何用户都可以拉取并使用这些镜像。 ### 静态和动态标识工具 静态和动态标识工具在Docker Hub上用于识别和分析公共容器映像。静态标识通常指的是在不运行镜像的情况下分析镜像的元数据和内容,例如检查Dockerfile中的指令、环境变量、端口映射等。动态标识则需要在容器运行时对容器的行为和性能进行监控和分析,如资源使用率、网络通信等。 ### 容器编排器与Docker映像 容器编排器是用于自动化容器部署、管理和扩展的工具。在Docker环境中,容器编排器能够自动化地启动、停止以及管理容器的生命周期。常见的容器编排器包括ECS和Kubernetes。 - **ECS (Elastic Container Service)**:是由亚马逊提供的容器编排服务,支持Docker容器,并提供了一种简单的方式来运行、停止以及管理容器化应用程序。 - **Kubernetes**:是一个开源平台,用于自动化容器化应用程序的部署、扩展和操作。它已经成为容器编排领域的事实标准。 ### 如何使用静态和动态标识工具 要使用这些静态和动态标识工具,首先需要获取并安装它们。从给定信息中了解到,可以通过克隆仓库或下载压缩包并解压到本地系统中。之后,根据需要针对不同的容器编排环境(如Dockerfile、ECS、Kubernetes)编写配置,以集成和使用这些检测工具。 ### Dockerfile中的工具使用 在Dockerfile中使用工具意味着将检测工具的指令嵌入到构建过程中。这可能包括安装检测工具的命令、运行容器扫描的步骤,以及将扫描结果集成到镜像构建流程中,确保只有通过安全和合规检查的容器镜像才能被构建和部署。 ### ECS与Kubernetes中的工具集成 在ECS或Kubernetes环境中,工具的集成可能涉及到创建特定的配置文件、定义服务和部署策略,以及编写脚本或控制器来自动执行检测任务。这样可以在容器编排的过程中实现实时监控,确保容器编排器只使用符合预期的、安全的容器镜像。 ### Linux系统下的操作 在Linux系统下操作这些工具,用户可能需要具备一定的系统管理和配置能力。这包括使用Linux命令行工具、管理文件系统权限、配置网络以及安装和配置软件包等。 ### 总结 综上所述,Docker Hub上的静态和动态标识工具提供了一种方法来检测和分析公共容器映像,确保这些镜像的安全性和可靠性。这些工具在Linux开发环境中尤为重要,因为它们帮助开发人员和运维人员确保他们的容器映像满足安全要求。通过在Dockerfile、ECS和Kubernetes中正确使用这些工具,可以提高应用程序的安全性,减少由于使用不安全的容器镜像带来的风险。此外,掌握Linux系统下的操作技能,可以更好地管理和维护这些工具,确保它们能够有效地发挥作用。
recommend-type

【扣子平台图像艺术探究:理论与实践的完美结合】:深入学习图像生成的艺术

# 1. 图像艺术的理论基础 艺术领域的每一个流派和技巧都有其理论基础。在图像艺术中,理论基础不仅是对艺术表现形式的认知,也是掌握艺术创作内在逻辑的关键。深入理解图像艺术的理论基础,能够帮助艺术家们在创作过程中更加明确地表达自己的艺术意图,以及更好地与观众沟通。 图像艺术的理论
recommend-type

增广路定理的证明

<think>嗯,用户想查找增广路定理的证明,关于图论和网络流算法的。我得先理解增广路定理是什么,然后找到相关的证明方法。根据之前的引用,尤其是引用5提到最大流最小割定理,里面有三个等价条件,其中第二个是残余网络中没有增广路径时,流就是最大流。这可能和增广路定理相关,也就是当残余网络中没有增广路时,当前流就是最大流,这可能就是增广路定理的内容。 首先,我需要明确增广路定理的陈述。根据引用5,增广路定理可能指的是:一个流是最大流当且仅当残余网络中不存在增广路径。这个定理的证明需要用到最大流最小割定理,也就是第三个条件,即最大流的流量等于最小割的容量。 证明的步骤可能需要分为两个方向:必要性(
recommend-type

Pulse:基于SwiftUI的Apple平台高效日志记录与网络监控

从给定文件信息中,我们可以提取出以下IT知识点进行详细阐述: **Pulse概览:** Pulse是一个专门针对Apple平台(如iOS、iPadOS、macOS等)的功能强大的日志记录系统。其设计目的是为了简化开发者在这些平台上调试网络请求和应用日志的过程。Pulse的核心特色是它使用SwiftUI来构建,这有助于开发者利用现代Swift语言的声明式UI优势来快速开发和维护。 **SwiftUI框架:** SwiftUI是一种声明式框架,由苹果公司推出,用于构建用户界面。与传统的UIKit相比,SwiftUI使用更加简洁的代码来描述界面和界面元素,它允许开发者以声明的方式定义视图和界面布局。SwiftUI支持跨平台,这意味着同一套代码可以在不同的Apple设备上运行,大大提高了开发效率和复用性。Pulse选择使用SwiftUI构建,显示了其对现代化、高效率开发的支持。 **Network Inspector功能:** Pulse具备Network Inspector功能,这个功能使得开发者能够在开发iOS应用时,直接从应用内记录和检查网络请求和日志。这种内嵌式的网络诊断能力非常有助于快速定位网络请求中的问题,如不正确的URL、不返回预期响应等。与传统的需要外部工具来抓包和分析的方式相比,这样的内嵌式工具大大减少了调试的复杂性。 **日志记录和隐私保护:** Pulse强调日志是本地记录的,并保证不会离开设备。这种做法对隐私保护至关重要,尤其是考虑到当前数据保护法规如GDPR等的严格要求。因此,Pulse的设计在帮助开发者进行问题诊断的同时,也确保了用户数据的安全性。 **集成和框架支持:** Pulse不仅仅是一个工具,它更是一个框架。它能够记录来自URLSession的事件,这意味着它可以与任何使用URLSession进行网络通信的应用或框架配合使用,包括但不限于Apple官方的网络库。此外,Pulse与使用它的框架(例如Alamofire)也能够良好配合,Alamofire是一个流行的网络请求库,广泛应用于Swift开发中。Pulse提供了一个PulseUI视图组件,开发者可以将其集成到自己的应用中,从而展示网络请求和其他事件。 **跨平台体验:** 开发者不仅可以在iOS应用中使用Pulse Console记录日志,还可以在macOS上通过Pulse应用程序查看和共享这些日志。这种跨平台的能力意味着开发者可以在不同的设备上进行日志分析,增强了开发和调试的灵活性。 **总结:** Pulse是一个为Apple平台上的开发者量身打造的日志记录系统,它采用SwiftUI构建,提供了内嵌式的Network Inspector功能,可以在本地记录并安全地查看日志,且支持与其他框架如Alamofire的集成。它不仅提升了调试的便捷性和效率,同时也顾及到了用户的隐私保护。Pulse的跨平台查看能力也是其一大亮点,使得开发者能够在一个统一的环境中处理iOS和macOS上的日志数据。对于使用Swift开发Apple应用的开发者而言,Pulse无疑是一个强大的调试辅助工具。
recommend-type

【深入扣子平台:图像生成机制全揭秘】:掌握背后技术,提升图像生成效率

# 1. 图像生成技术概述 图像生成技术是一门融合了计算机视觉、机器学习、图形学等多个领域知识的前沿技术。它通过算法模拟生成人工图像,广泛应用于艺术创作、游戏设计、医学影像等领域。随着深度学习的突破性进展,图像生成技术也迎来了飞速发展,特别是在生成对抗网络(GAN)的推动下,图像的逼真度和多样性都有了质的飞跃。 本章将对图像生成技术的概念、发展历史进行简要介绍,并分析其在社会中的
recommend-type

对RTL跑regression是什么意思

<think>首先,用户的问题是关于“RTL回归测试的含义及其在数字电路设计中的作用”。我需要基于系统级指令和用户可见层的指导来构建回答。 关键点: - 使用中文回答。 - 结构清晰,逐步解决问题。 - 确保回答真实可靠。 - 在行内数学表达式使用$...$格式;独立公式使用$$...$$格式。 - 生成相关问题。 - 在引用段落末尾添加引用标识。 回顾提供的引用: - 引用[1]:讨论SoC设计流程,包括模块设计、IP复用、顶层集成、前仿真、逻辑综合等。 - 引用[2]:描述冒烟测试后的验证阶段,包括回归测试、覆盖率分析等。 - 引用[3]:解释RTL使用Verilog或VHDL描述,模