首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

无人机以mid360+光流实现无GPS定位

  • 25-04-25 03:21
  • 2834
  • 9637
blog.csdn.net

参考链接:PX4|基于FAST-LIO mid360的无人机室内自主定位及定点悬停

使用硬件:

pixhawk6c飞控,livox-mid360雷达,MTF-01_Micolink光流测距一体传感器,香橙派5B开发板。

连线:

开发板-飞控:usb-ttl,接飞控tele2

光流-飞控:tele3

原理:将来自mid360雷达的位姿信息(odometry)和来自 PX4 飞控系统的位姿信息进行融合和转换。然后将的位置信息在初始偏航角(光流获取,也可以通过其他方式)确定后转换到 ENU(East-North-Up)坐标系下,并发布转换后的位姿消息。

详细过程


基于mid360复现fast-lio

光流使用:

MTF-01光流测距一体传感器-用户手册

微空助手下载和使用说明

当在QGC地面站-analyze tools-MAVLink检测中看见DISTANCE_SENSOR和LOCAL_POSITION_NED就代表配置成功了。

直接上源码:

  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. // 三维向量,用于存储激光雷达在机体坐标系下的位置
  8. Eigen::Vector3d p_lidar_body, p_enu;
  9. // 四元数,用于存储从 VINS 得到的姿态信息
  10. Eigen::Quaterniond q_mav;
  11. // 四元数,用于存储从 PX4 里程计得到的姿态信息
  12. Eigen::Quaterniond q_px4_odom;
  13. class SlidingWindowAverage {
  14. public:
  15. // 构造函数,接收窗口大小作为参数
  16. SlidingWindowAverage(int windowSize) : windowSize(windowSize), windowSum(0.0) {}
  17. // 添加数据的方法
  18. double addData(double newData) {
  19. bool needReset = false;
  20. // 如果队列不为空且新数据与队尾数据差值大于 0.01,则需要重置队列
  21. if (!dataQueue.empty() && std::fabs(newData - dataQueue.back()) > 0.01) {
  22. needReset = true;
  23. }
  24. dataQueue.push(newData);
  25. windowSum += newData;
  26. // 如果队列大小超过窗口大小,弹出队首元素并更新总和
  27. if (dataQueue.size() > windowSize) {
  28. windowSum -= dataQueue.front();
  29. dataQueue.pop();
  30. }
  31. // 如果需要重置或者队列大小小于窗口大小,直接将平均值设为新数据
  32. if (needReset || dataQueue.size() < windowSize) {
  33. windowAvg = newData;
  34. } else {
  35. // 否则计算并更新平均值
  36. windowAvg = windowSum / dataQueue.size();
  37. }
  38. return windowAvg;
  39. }
  40. // 获取队列大小的方法
  41. int get_size() {
  42. return dataQueue.size();
  43. }
  44. // 获取平均值的方法
  45. double get_avg() {
  46. return windowAvg;
  47. }
  48. private:
  49. int windowSize;
  50. double windowSum;
  51. double windowAvg;
  52. std::queue<double> dataQueue;
  53. };
  54. // 从四元数计算偏航角的函数
  55. double fromQuaternion2yaw(const Eigen::Quaterniond& q) {
  56. double yaw = std::atan2(2 * (q.x()*q.y() + q.w()*q.z()), q.w()*q.w() + q.x()*q.x() - q.y()*q.y() - q.z()*q.z());
  57. return yaw;
  58. }
  59. int main(int argc, char **argv) {
  60. ros::init(argc, argv, "vins_to_mavros");
  61. ros::NodeHandle nh("~");
  62. // 订阅 VINS 的里程计消息
  63. ros::Subscriber slam_sub = nh.subscribe("/Odometry", 100, [&](const nav_msgs::Odometry::ConstPtr& msg) {
  64. // 将消息中的位置信息存储到向量中
  65. p_lidar_body = Eigen::Vector3d(msg->pose.pose.position.x, msg->pose.pose.position.y, msg->pose.pose.position.z);
  66. // 将消息中的姿态信息存储到四元数中
  67. q_mav = Eigen::Quaterniond(msg->pose.pose.orientation.w, msg->pose.pose.orientation.x, msg->pose.pose.orientation.y, msg->pose.pose.orientation.z);
  68. });
  69. // 订阅 PX4 的里程计消息
  70. ros::Subscriber px4_odom_sub = nh.subscribe("/mavros/local_position/odom", 5, [&](const nav_msgs::Odometry::ConstPtr& msg) {
  71. // 将消息中的姿态信息存储到四元数中
  72. q_px4_odom = Eigen::Quaterniond(msg->pose.pose.orientation.w, msg->pose.pose.orientation.x, msg->pose.pose.orientation.y, msg->pose.pose.orientation.z);
  73. // 将 PX4 里程计的偏航角添加到滑动平均类中
  74. swa.addData(fromQuaternion2yaw(q_px4_odom));
  75. });
  76. // 发布转换后的位姿消息
  77. ros::Publisher vision_pub = nh.advertise("/mavros/vision_pose/pose", 10);
  78. // 设置发布频率
  79. ros::Rate rate(20.0);
  80. int windowSize = 8;
  81. SlidingWindowAverage swa(windowSize);
  82. float init_yaw = 0.0;
  83. bool init_flag = false;
  84. Eigen::Quaterniond init_q;
  85. while (ros::ok()) {
  86. // 如果滑动平均队列大小达到窗口大小且未初始化,则进行初始化
  87. if (swa.get_size() == windowSize &&!init_flag) {
  88. init_yaw = swa.get_avg();
  89. init_flag = true;
  90. // 根据初始偏航角创建初始四元数
  91. init_q = Eigen::AngleAxisd(init_yaw, Eigen::Vector3d::UnitZ())
  92. * Eigen::AngleAxisd(0.0, Eigen::Vector3d::UnitY())
  93. * Eigen::AngleAxisd(0.0, Eigen::Vector3d::UnitX());
  94. }
  95. if (init_flag) {
  96. geometry_msgs::PoseStamped vision;
  97. // 根据初始四元数将激光雷达在机体坐标系下的位置转换到 ENU 坐标系下
  98. p_enu = init_q * p_lidar_body;
  99. vision.pose.position.x = p_enu[0];
  100. vision.pose.position.y = p_enu[1];
  101. vision.pose.position.z = p_enu[2];
  102. vision.pose.orientation.x = q_mav.x();
  103. vision.pose.orientation.y = q_mav.y();
  104. vision.pose.orientation.z = q_mav.z();
  105. vision.pose.orientation.w = q_mav.w();
  106. vision.header.stamp = ros::Time::now();
  107. vision_pub.publish(vision);
  108. ROS_INFO("\nposition in enu:\n x: %.18f\n y: %.18f\n z: %.18f\norientation of lidar:\n x: %.18f\n y: %.18f\n z: %.18f\n w: %.18f",
  109. p_enu[0], p_enu[1], p_enu[2], q_mav.x(), q_mav.y(), q_mav.z(), q_mav.w());
  110. }
  111. ros::spinOnce();
  112. rate.sleep();
  113. }
  114. return 0;
  115. }

依次运行:

启动雷达

roslaunch livox_ros_driver2 msg_MID360.launch

 启动fast-lio

roslaunch fast_lio mapping_mid360.launch

 启动mavros

roslaunch mavros px4.launch

 启动上述雷达定位节点

rosrun mid2px4_pkg mid2px4_node

 启动offboard

rosrun offboard_run offboard_run_node

就可以实现真机飞行了

注:本文转载自blog.csdn.net的逃跑的木可的文章"https://blog.csdn.net/weixin_67505885/article/details/143215008"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

117
前沿技术
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top