多线激光雷达ndt定位与movebase结合的想法

请添加图片描述

movebase
针对movebase中tf变换关系的要求
里程计节点应发布 odom到 baselink的变换信息
定位节点,计算出 map到 baselink的变换关系,但不发布map到baselink的变换信息
定位节点应 根据 里程计节点发布的odom 到baselink的信息,计算出 map到 odom的变换信息并发布

如果定位节点 计算 map到baselink的变换关系,并能配置发布一个 map到 baselink_footprint的信息,本节点可以根据定位节点和里程计节点,推算出 map到odom的关系,并发布tf

ndt定位
能结算出map到baselink的tf,修改部分代码不发布这个tf

static int _tf_use_baselink_footprint = 0;//zzz
  private_nh.getParam("tf_use_baselink_footprint", _tf_use_baselink_footprint);//zzz


    // Send TF "/base_link" to "/map"
    transform.setOrigin(tf::Vector3(current_pose.x, current_pose.y, current_pose.z));
    transform.setRotation(current_q);
    //    br.sendTransform(tf::StampedTransform(transform, current_scan_time, "/map", "/base_link"));
    if (_use_local_transform == true)
    {
      if (_tf_use_baselink_footprint){//zzz add
        br.sendTransform(tf::StampedTransform(local_transform * transform, current_scan_time, "/map", "/base_link_footprint"));
      }else{
        br.sendTransform(tf::StampedTransform(local_transform * transform, current_scan_time, "/map", "/base_link"));
      }
    }
    else
    {
      if (_tf_use_baselink_footprint){//zzz add
        br.sendTransform(tf::StampedTransform(transform, current_scan_time, "/map", "/base_link_footprint"));
      }else{
        br.sendTransform(tf::StampedTransform(transform, current_scan_time, "/map", "/base_link"));
      }
    }

适配节点

#!/usr/bin/env python
# -*- coding: utf-8 -*-


#import roslib

import rospy
import math
import tf
import geometry_msgs.msg
from geometry_msgs.msg import PoseStamped
import tf_conversions as tfc

#zzz------------------------------
#针对movebase中tf变换关系的要求
#里程计节点应发布 odom到 baselink的变换信息
#定位节点,计算出 map到 baselink的变换关系,但不发布map到baselink的变换信息
#定位节点应 根据 里程计节点发布的odom 到baselink的信息,计算出 map到 odom的变换信息并发布

#如果定位节点 计算 map到baselink的变换关系,并能配置发布一个 map到 baselink_footprint的信息,本节点可以根据定位节点和里程计节点,推算出 map到odom的关系,并发布tf


class MapOdom():

    def __init__(self):
        rospy.init_node('tf_map_odom', anonymous=True)
        self.listener = tf.TransformListener()
        self.ps_pub = rospy.Publisher("map_odom_pose", PoseStamped, queue_size=1)
        self.frame_map = rospy.get_param("~frame_map", "map")
        self.frame_odom = rospy.get_param("~frame_odom", "odom")
        self.frame_base_link = rospy.get_param("~frame_base_link", "base_link")
        self.frame_base_link_location = rospy.get_param("~frame_base_link_location", "base_link_footprint")

        self.test_location = rospy.get_param("~test_location", 1)
        self.rate_hz = rospy.get_param("~rate", 10)
        self.rate = rospy.Rate(self.rate_hz)
        x,y,z,w=0,0,0,1
        quaternion=(x,y,z,w)
        # 将四元数转换为旋转矩阵
        rotation_matrix = tf.transformations.quaternion_matrix(quaternion)
        print rotation_matrix

        rotation_matrix =tf.transformations.inverse_matrix(rotation_matrix)
        print rotation_matrix

        tx,ty,tz=1,2,3
        trans = [tx,ty,tz]
        translation_matrix = tf.transformations.translation_matrix(trans)

        rotation_matrix =tf.transformations.concatenate_matrices(translation_matrix, rotation_matrix)
        print rotation_matrix


    def tf_Q2M(self,x,y,z,w,tx,ty,tz):#输入四元数 + 位移
        
        # 将四元数转换为旋转矩阵
        rotation_matrix = tf.transformations.quaternion_matrix((x,y,z,w))
        translation_matrix = tf.transformations.translation_matrix((tx,ty,tz))
        return tf.transformations.concatenate_matrices(translation_matrix, rotation_matrix)
    #主要的计算:矩mo=逆(矩ob* 逆(矩mb))
    def run(self):
        #rospy.spin()

        c=1
        while(not rospy.is_shutdown()):
            self.rate.sleep()
            c=c+1
            print c
            if self.test_location:
                br = tf.TransformBroadcaster()
                br.sendTransform((0,0,0),
                         (0,0,0,1),
                         rospy.get_rostime(),
                         self.frame_base_link_location,
                         self.frame_map) 

            try:
                now = rospy.Time.now()


                #print self.listener.frameExists("base_link")
                #print self.listener.frameExists("odom")
                if self.listener.frameExists(self.frame_base_link) :#and self.listener.frameExists("map"):#20211229
                    # listener.waitForTransform("base_link", "map", rospy.Time(), rospy.Duration(4.0))
                    #t = self.listener.getLatestCommonTime("base_link", "odom")
                    #position, quaternion = self.listener.lookupTransform("odom","base_link",  t)
                    #获取odom---->baselink

                    t = self.listener.getLatestCommonTime(self.frame_base_link, self.frame_odom)
                    position, quaternion = self.listener.lookupTransform(self.frame_odom,self.frame_base_link,  t)
                    M_ob=self.tf_Q2M(quaternion[0],quaternion[1],quaternion[2],quaternion[3],position[0],position[1],position[2])



                    #t = self.listener.getLatestCommonTime("base_link_footprint", "map")
                    #position, quaternion = self.listener.lookupTransform("map","base_link_footprint",  t)
                    #获取map---->base_link_footprint(base_link)
                    t = self.listener.getLatestCommonTime(self.frame_base_link_location, self.frame_map)
                    position, quaternion = self.listener.lookupTransform(self.frame_map,self.frame_base_link_location,  t) 


                    M_mb=self.tf_Q2M(quaternion[0],quaternion[1],quaternion[2],quaternion[3],position[0],position[1],position[2])
                    M_bm=tf.transformations.inverse_matrix(M_mb)

                   
                    #map---->odom
                    
                    M_om=tf.transformations.concatenate_matrices(M_ob,M_bm)
                    M_mo=tf.transformations.inverse_matrix(M_om)
                    #print "zzzbbb"
                    #print M_mo
                    #print "zzzeee"
                    # 位移
                    T_mo=(M_mo[0][3],M_mo[1][3],M_mo[2][3])
                    # 将矩阵转换为四元数 
                    Q_mo=tf.transformations.quaternion_from_matrix(M_mo)
                    
                    #print Q_mo

                    # 发布tf 
                    br = tf.TransformBroadcaster()
                    br.sendTransform(T_mo,
                         Q_mo,
                         rospy.get_rostime(),
                         self.frame_odom,
                         self.frame_map) 

                else:
                    rospy.loginfo("frame not exists")
            except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
                rospy.loginfo("failed: lookupTransform")
                continue





    #test
    def run2test(self):

        c=1
        while(not rospy.is_shutdown()):
            self.rate.sleep()
            c=c+1
            print c
            br = tf.TransformBroadcaster()
            br.sendTransform((0,0,0),
                         (0,0,0,1),
                         rospy.get_rostime(),
                         "base_link_footprint",
                         "map") 

            try:
                now = rospy.Time.now()


                print self.listener.frameExists("base_link")
                print self.listener.frameExists("odom")
                if self.listener.frameExists("base_link") :#and self.listener.frameExists("map"):#20211229
                    # listener.waitForTransform("base_link", "map", rospy.Time(), rospy.Duration(4.0))
                    t = self.listener.getLatestCommonTime("base_link", "odom")
                    position, quaternion = self.listener.lookupTransform("odom","base_link",  t)
                    #odom---->baselink


                    M_ob=self.tf_Q2M(quaternion[0],quaternion[1],quaternion[2],quaternion[3],position[0],position[1],position[2])

                    qInvert = tfc.transformations.quaternion_inverse
                    qMultiply = tfc.transformations.quaternion_multiply
                    inv_quat = qInvert(quaternion)
                    r_quat = qMultiply(inv_quat, quaternion)
                    # 对四元数进行逆变换
                    #inv_quat = tf.transformations.quaternion_inverse(quaternion)
                    #inv_quat = rospy.normalize_quaternion(inv_quat)
                    #inv_quat = rospy.quaternion_inverse(quaternion)
                    #r_quat=quaternion*inv_quat
                    pos =(position[0]*-1,position[1]*-1,position[2]*-1)#*-1
                    # rot=tf.transformations.quaternion_from_euler(self.pose_roll+self.adjust_roll,self.pose_pitch+self.adjust_pitch,self.pose_yaw+self.adjust_yaw)



                    br = tf.TransformBroadcaster()
                    br.sendTransform(pos,
                         r_quat,
                         rospy.get_rostime(),
                         "base_link_test",
                         "odom") 
                    print("逆变换后的四元数: x={}, y={}, z={}, w={}".format(inv_quat[0], inv_quat[1], inv_quat[2], inv_quat[3]))
                    e=quaternion*inv_quat
                    print("四元数: x={}, y={}, z={}, w={}".format(e[0], e[1], e[2], e[3]))
                    print position
                    print quaternion
                    pose = PoseStamped()
                    pose.header.stamp = rospy.Time.now()
                    pose.header.frame_id = "map"
                    pose.pose.position.x = position[0]
                    pose.pose.position.y = position[1]
                    pose.pose.position.z = position[2]

                    pose.pose.orientation.x = quaternion[0]
                    pose.pose.orientation.y = quaternion[1]
                    pose.pose.orientation.z = quaternion[2]
                    pose.pose.orientation.w = quaternion[3]
                    self.ps_pub.publish(pose)
                    rospy.loginfo("xyz| {},{},{}".format(position[0], position[1], position[2]))

                    t = self.listener.getLatestCommonTime("base_link_footprint", "map")
                    position, quaternion = self.listener.lookupTransform("map","base_link_footprint",  t)
                    M_mb=self.tf_Q2M(quaternion[0],quaternion[1],quaternion[2],quaternion[3],position[0],position[1],position[2])
                    M_bm=tf.transformations.inverse_matrix(M_mb)

                    inv_quat1 = qInvert(quaternion)
                    r_quat = qMultiply(inv_quat1, quaternion)

                    pos1 =(position[0]*-1,position[1]*-1,position[2]*-1)#*-1

                    
                    M_om=tf.transformations.concatenate_matrices(M_ob,M_bm)
                    M_mo=tf.transformations.inverse_matrix(M_om)
                    print "zzzbbb"
                    print M_mo
                    print "zzzeee"
                    T_mo=(M_mo[0][3],M_mo[1][3],M_mo[2][3])
                    Q_mo=tf.transformations.quaternion_from_matrix(M_mo)
                    
                    print Q_mo


                    br = tf.TransformBroadcaster()
                    br.sendTransform(T_mo,
                         Q_mo,
                         rospy.get_rostime(),
                         "odom",
                         "map") 

                    #inv_quat:Q2    inv_quat1:Q1
                    Q2=inv_quat1
                    Q1=inv_quat
                    #计算Q2相对于Q1的旋转。‌
                    #将Q1和Q2归一化,使其长度为1。这可以通过将四元数除以其模长来实现。

                    #计算Q2的共轭四元数Q2_conj。共轭四元数可以通过将Q2的虚部取负来得到。
                    Q2_conj=(Q2[0]*-1,Q2[1]*-1,Q2[2]*-1,Q2[3])
                    #计算相对旋转的四元数Q_relative = Q2_conj * Q1。这里的乘法是四元数的乘法运算。
                    Q_relative = qMultiply(Q2_conj, Q1)
                    #将Q_relative归一化,得到单位四元数。
                    #从单位四元数中提取旋转信息。可以通过将单位四元数转换为旋转矩阵或欧拉角来表示相对旋转。

                    #r_posi=(pos1[0]-pos[0],pos1[1]-pos[1],pos1[2]-pos[2])
                    r_posi=(pos[0]-pos1[0],pos[1]-pos1[1],pos[2]-pos1[2])

                    '''
                    br = tf.TransformBroadcaster()
                    br.sendTransform(r_posi,
                         Q_relative,
                         rospy.get_rostime(),
                         "odom",
                         "map") 
                    '''
                    #map---->baselink
                else:
                    rospy.loginfo("frame not exists")
            except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
                rospy.loginfo("failed: lookupTransform")
                continue

        print "exit!!!!!!!!!!!"


if __name__ == '__main__':
    import os
    print os.environ['ROS_MASTER_URI']
    cp = MapOdom()
    cp.run()
   

3d点云转换成2d地图
roslaunch autolabor_navigation_launch 3d2dmap.launch

点云转换laser 要求points_noground话题
roslaunch pointcloud_to_laserscan pointcloud_to_laserscan.launch

laser里程计 要求/lidar_16_scan话题,发布 odom->base_link
roslaunch laser_scan_matcher_odometry laser_scan_matcher_odometry.launch

多线雷达定位,配置tf_use_baselink_footprint不发布map->baselink 发布map->baselink_footprint
roslaunch lidar_localizer ndt_matching.launch method_type:=0 use_odom:=False use_imu:=False imu_upside_down:=False imu_topic:= get_height:=False output_log_data:=False tf_use_baselink_footprint:=1

计算 map->odom的变换, 依赖tf: 定位map->baselink_footprint和里程计 odom->base_link
roslaunch r2ware_car_labor r2ware_tf_map_odom.launch

多线雷达movebase导航
roslaunch autolabor_navigation_launch r2ware_navigation_lidar_16.launch

仅需线控底盘和多线激光雷达,movebase导航走起~

<think>嗯,用户问的是关于“okg是movebase,两个节点分别是move_base和gazebo”。首先,我需要确认用户的问题是否正确,或者是否存在拼写错误。这里的“okg”可能是用户输入时的笔误,正确的应该是“ROS中的move_base”框架。接着,用户提到两个节点:move_base和gazebo。这里需要明确的是,Gazebo其实是一个机器人仿真工具,并不是一个节点,而是一个独立的仿真环境。不过,在ROS中,Gazebo通常会通过插件ROS节点进行通信,例如发布传感器数据或接收控制命令。 首先,我应该解释move_base在ROS中的作用。move_base是ROS导航栈中的一个核心节点,负责路径规划和控制,将全局和局部规划结合起来,帮助机器人导航到目标位置。用户可能想了解move_base的工作原理以及它其他组件(如Gazebo)的交互方式。 然后,关于Gazebo,需要说明它是一个3D动态仿真器,用于模拟机器人及其环境。在ROS中,通常使用gazebo_ros包来集成Gazebo和ROS,这样Gazebo中的传感器数据可以通过ROS话题发布,控制命令也可以通过ROS订阅。所以,当用户提到“两个节点”时,可能是指在使用move_base进行导航时,需要同时运行Gazebo仿真环境和move_base节点,两者通过ROS进行通信。 接下来,可能需要详细说明这两个部分如何协同工作。例如,在仿真中,Gazebo提供机器人的传感器数据(如激光雷达、摄像头)和位姿信息,这些数据通过ROS话题传输给move_base节点。move_base根据这些信息进行路径规划,并生成速度指令发送回Gazebo中的机器人模型,驱动机器人移动。 此外,用户可能对如何设置和运行这两个节点感兴趣。可能需要提及启动文件(launch files)的使用,如何配置move_base的参数(如代价地图、全局局部规划器),以及如何确保Gazebo中的模型ROS导航栈正确对接。 还需要考虑用户可能的背景。如果用户是ROS新手,可能需要更基础的介绍,包括ROS的基本概念如节点、话题、服务等。如果用户有一定经验,可能需要更深入的技术细节,比如如何处理实际应用中的导航问题,或是调试move_base和Gazebo之间的常见问题。 最后,检查是否有遗漏或误解。例如,用户是否可能混淆了节点和仿真环境?是否需要澄清Gazebo本身不是一个节点,而是通过ROS节点系统交互?是否需要提供示例代码或官方文档链接帮助用户进一步学习? 总结下来,回答的结构应该是先纠正可能的拼写错误,明确move_base和Gazebo的角色,解释它们在ROS导航中的作用,描述它们如何通过ROS通信,并可能提供配置和使用的简要步骤,最后建议学习资源或进一步阅读材料。</think>在机器人操作系统(ROS)中,`move_base` 是导航功能包集(Navigation Stack)的核心节点,用于实现机器人的路径规划运动控制。而 **Gazebo** 是一个高保真机器人仿真工具,常用于模拟机器人及其所处环境。以下是两者的关键介绍及协作关系: --- ### **1. `move_base` 节点** - **功能**: `move_base` 是 ROS 导航栈的核心节点,负责将全局路径规划(如 `global_planner`)局部路径规划(如 `dwa_local_planner`)结合,协调机器人从起点到目标点的导航任务。 - **全局规划**:基于静态地图(如 SLAM 生成的地图)生成全局路径。 - **局部规划**:根据实时传感器数据(如激光雷达)避障并动态调整路径。 - **控制**:输出速度指令(`cmd_vel`)驱动机器人底盘。 - **输入/输出**: - 订阅:目标位姿(`move_base_simple/goal`)、传感器数据(如 `/scan`)、地图(`/map`)。 - 发布:速度指令(`/cmd_vel`)。 --- ### **2. Gazebo 仿真环境** - **功能**: 提供虚拟的机器人模型、传感器(如激光雷达、摄像头)和物理环境(如障碍物、地形)。通过 `gazebo_ros` 插件 ROS 通信: - 发布传感器数据(如 `/scan` 对应激光雷达)。 - 订阅控制指令(如 `/cmd_vel` 驱动机器人模型)。 - **协作角色**: Gazebo 模拟真实世界的物理行为,为 `move_base` 提供传感器输入并执行其输出的运动指令,构成闭环仿真测试。 --- ### **两者的协作流程** 1. **Gazebo** 模拟机器人,持续发布传感器数据(如激光雷达 `/scan`)和机器人位姿(`/odom`)。 2. **`move_base`** 接收目标位姿(如通过 Rviz 设置),结合传感器数据和地图,计算全局和局部路径。 3. **`move_base`** 发布速度指令 `/cmd_vel` 到 Gazebo 中的机器人模型,控制其移动。 4. **Gazebo** 根据物理引擎更新机器人状态,形成闭环反馈。 --- ### **典型应用场景** - **开发阶段**:在 Gazebo 中验证 `move_base` 的导航算法,无需真实机器人。 - **参数调试**:调整代价地图(`costmap`)、规划器参数(如 `base_local_planner`)以优化避障效果。 - **多机器人协作**:在 Gazebo 中模拟多机协同导航。 --- ### **快速启动示例** 通过 ROS 启动文件同时运行: ```xml <launch> <!-- 启动 Gazebo 仿真环境 --> <include file="$(find gazebo_ros)/launch/empty_world.launch"> <arg name="world_name" value="your_custom_world.world"/> </include> <!-- 机器人模型到 Gazebo --> <node name="spawn_robot" pkg="gazebo_ros" type="spawn_model" args="-urdf -file my_robot.urdf -model my_robot" /> <!-- 启动 move_base 节点 --> <node pkg="move_base" type="move_base" name="move_base" output="screen"> <rosparam file="$(find my_robot_nav)/config/costmap_common_params.yaml" command="load" ns="global_costmap" /> <rosparam file="$(find my_robot_nav)/config/costmap_common_params.yaml" command="load" ns="local_costmap" /> <rosparam file="$(find my_robot_nav)/config/local_costmap_params.yaml" command="load" /> <rosparam file="$(find my_robot_nav)/config/global_costmap_params.yaml" command="load" /> <rosparam file="$(find my_robot_nav)/config/base_local_planner_params.yaml" command="load" /> </node> </launch> ``` --- ### **学习资源** - ROS Wiki `move_base`:http://wiki.ros.org/move_base - Gazebo 官方教程:http://gazebosim.org/tutorials - 导航栈配置指南:http://wiki.ros.org/navigation/Tutorials 通过结合 `move_base` 和 Gazebo,开发者可以在仿真环境中高效验证导航算法,降低硬件测试成本。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值