从ORB_SLAM中发布ROS位姿话题(stereo)

12 篇文章 2 订阅
3 篇文章 0 订阅

之前调试了ORB_SLAM2的gazebo仿真,现在需要在ROS中使用到ORB_SLAM2的位姿,但是ORB_SLAM2本身是没有位姿的ROS话题输出的,参考了github上相关问题的探讨:Get Pose Information from ORBSLAM最后成功得到了ORB_SLAM2运行时机器人的位姿反馈。

分析源代码最终会发现对于ORB_SLAM2而言,位姿由以下处理函数返回:

mpSLAM->TrackStereo(imLeft,imRight,cv_ptrLeft->header.stamp.toSec());

所以我们可以调用该处理函数:

Tcw = mpSLAM->TrackStereo(imLeft,imRight,cv_ptrLeft->header.stamp.toSec());

这里Tcw为定义的一个矩阵:

cv::Mat Tcw;

返回得到一个4x4的矩阵信息,该矩阵包含了三个旋转分量以及三个平移分量。我们对该矩阵进行处理并发布出最后的位姿信息:

geometry_msgs::PoseStamped pose;
pose.header.stamp = ros::Time::now();
pose.header.frame_id ="map";

cv::Mat Rwc = Tcw.rowRange(0,3).colRange(0,3).t(); // Rotation information
cv::Mat twc = -Rwc*Tcw.rowRange(0,3).col(3); // translation information
vector<float> q = ORB_SLAM2::Converter::toQuaternion(Rwc);

tf::Transform new_transform;
new_transform.setOrigin(tf::Vector3(twc.at<float>(0, 0), twc.at<float>(0, 1), twc.at<float>(0, 2)));

tf::Quaternion quaternion(q[0], q[1], q[2], q[3]);
new_transform.setRotation(quaternion);

tf::poseTFToMsg(new_transform, pose.pose);
pose_pub.publish(pose);

注意这里使用了publish需要在前面声明:

ros::Publisher pose_pub = nh.advertise<geometry_msgs::PoseStamped>("orb_pose", 100);

以及几个相关的头文件:

#include <geometry_msgs/PoseStamped.h> 
#include <tf/tf.h> 
#include <tf/transform_datatypes.h> 
#include"../../../include/Converter.h"

所有的这些程序添加在ros_stereo.cc文件中。最后修改完的文件如下:


#include<iostream>
#include<algorithm>
#include<fstream>
#include<chrono>

#include<ros/ros.h>
#include <cv_bridge/cv_bridge.h>
#include <message_filters/subscriber.h>
#include <message_filters/time_synchronizer.h>
#include <message_filters/sync_policies/approximate_time.h>

#include<opencv2/core/core.hpp>

#include"../../../include/System.h"

#include <geometry_msgs/PoseStamped.h> //modify
#include <tf/tf.h> 
#include <tf/transform_datatypes.h> 
#include"../../../include/Converter.h"

using namespace std;

class ImageGrabber
{
public:
    ImageGrabber(ORB_SLAM2::System* pSLAM):mpSLAM(pSLAM){}
	//
    void GrabStereo(const sensor_msgs::ImageConstPtr& msgLeft,const sensor_msgs::ImageConstPtr& msgRight);

    ORB_SLAM2::System* mpSLAM;
    bool do_rectify;
    cv::Mat M1l,M2l,M1r,M2r;
};

int main(int argc, char **argv)
{
    ros::init(argc, argv, "RGBD");
    ros::start();

    if(argc != 4)
    {
        cerr << endl << "Usage: rosrun ORB_SLAM2 Stereo path_to_vocabulary path_to_settings do_rectify" << endl;
        ros::shutdown();
        return 1;
    }    

    // Create SLAM system. It initializes all system threads and gets ready to process frames.
    ORB_SLAM2::System SLAM(argv[1],argv[2],ORB_SLAM2::System::STEREO,true);

    ImageGrabber igb(&SLAM);

    stringstream ss(argv[3]);
	ss >> boolalpha >> igb.do_rectify;

    if(igb.do_rectify)
    {      
        // Load settings related to stereo calibration
        cv::FileStorage fsSettings(argv[2], cv::FileStorage::READ);
        if(!fsSettings.isOpened())
        {
            cerr << "ERROR: Wrong path to settings" << endl;
            return -1;
        }

        cv::Mat K_l, K_r, P_l, P_r, R_l, R_r, D_l, D_r;
        fsSettings["LEFT.K"] >> K_l;
        fsSettings["RIGHT.K"] >> K_r;

        fsSettings["LEFT.P"] >> P_l;
        fsSettings["RIGHT.P"] >> P_r;

        fsSettings["LEFT.R"] >> R_l;
        fsSettings["RIGHT.R"] >> R_r;

        fsSettings["LEFT.D"] >> D_l;
        fsSettings["RIGHT.D"] >> D_r;

        int rows_l = fsSettings["LEFT.height"];
        int cols_l = fsSettings["LEFT.width"];
        int rows_r = fsSettings["RIGHT.height"];
        int cols_r = fsSettings["RIGHT.width"];

        if(K_l.empty() || K_r.empty() || P_l.empty() || P_r.empty() || R_l.empty() || R_r.empty() || D_l.empty() || D_r.empty() ||
                rows_l==0 || rows_r==0 || cols_l==0 || cols_r==0)
        {
            cerr << "ERROR: Calibration parameters to rectify stereo are missing!" << endl;
            return -1;
        }

        cv::initUndistortRectifyMap(K_l,D_l,R_l,P_l.rowRange(0,3).colRange(0,3),cv::Size(cols_l,rows_l),CV_32F,igb.M1l,igb.M2l);
        cv::initUndistortRectifyMap(K_r,D_r,R_r,P_r.rowRange(0,3).colRange(0,3),cv::Size(cols_r,rows_r),CV_32F,igb.M1r,igb.M2r);
    }

    ros::NodeHandle nh;

    message_filters::Subscriber<sensor_msgs::Image> left_sub(nh, "/camera/left/image_raw", 1);
    message_filters::Subscriber<sensor_msgs::Image> right_sub(nh, "camera/right/image_raw", 1);
    typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::Image, sensor_msgs::Image> sync_pol;
    message_filters::Synchronizer<sync_pol> sync(sync_pol(10), left_sub,right_sub);
    sync.registerCallback(boost::bind(&ImageGrabber::GrabStereo,&igb,_1,_2));
	ros::Publisher pose_pub = nh.advertise<geometry_msgs::PoseStamped>("orb_pose", 100);//modify
    ros::spin();

    // Stop all threads
    SLAM.Shutdown();

    // Save camera trajectory
    SLAM.SaveKeyFrameTrajectoryTUM("KeyFrameTrajectory_TUM_Format.txt");
    SLAM.SaveTrajectoryTUM("FrameTrajectory_TUM_Format.txt");
    SLAM.SaveTrajectoryKITTI("FrameTrajectory_KITTI_Format.txt");

    ros::shutdown();

    return 0;
}

void ImageGrabber::GrabStereo(const sensor_msgs::ImageConstPtr& msgLeft,const sensor_msgs::ImageConstPtr& msgRight)
{
    // Copy the ros image message to cv::Mat.
    cv_bridge::CvImageConstPtr cv_ptrLeft;
    try
    {
        cv_ptrLeft = cv_bridge::toCvShare(msgLeft);
    }
    catch (cv_bridge::Exception& e)
    {
        ROS_ERROR("cv_bridge exception: %s", e.what());
        return;
    }

    cv_bridge::CvImageConstPtr cv_ptrRight;
    try
    {
        cv_ptrRight = cv_bridge::toCvShare(msgRight);
    }
    catch (cv_bridge::Exception& e)
    {
        ROS_ERROR("cv_bridge exception: %s", e.what());
        return;
    }

    if(do_rectify)
    {
        cv::Mat imLeft, imRight;
        cv::remap(cv_ptrLeft->image,imLeft,M1l,M2l,cv::INTER_LINEAR);
        cv::remap(cv_ptrRight->image,imRight,M1r,M2r,cv::INTER_LINEAR);
        mpSLAM->TrackStereo(imLeft,imRight,cv_ptrLeft->header.stamp.toSec());
    }
    else
    {
		cv::Mat Tcw;//modify
        //mpSLAM->TrackStereo(cv_ptrLeft->image,cv_ptrRight->image,cv_ptrLeft->header.stamp.toSec());
		Tcw = mpSLAM->TrackStereo(imLeft,imRight,cv_ptrLeft->header.stamp.toSec());
		geometry_msgs::PoseStamped pose;
        pose.header.stamp = ros::Time::now();
        pose.header.frame_id ="map";

        cv::Mat Rwc = Tcw.rowRange(0,3).colRange(0,3).t(); // Rotation information
        cv::Mat twc = -Rwc*Tcw.rowRange(0,3).col(3); // translation information
        vector<float> q = ORB_SLAM2::Converter::toQuaternion(Rwc);

        tf::Transform new_transform;
        new_transform.setOrigin(tf::Vector3(twc.at<float>(0, 0), twc.at<float>(0, 1), twc.at<float>(0, 2)));

        tf::Quaternion quaternion(q[0], q[1], q[2], q[3]);
        new_transform.setRotation(quaternion);

        tf::poseTFToMsg(new_transform, pose.pose);
        pose_pub.publish(pose);
    }

}
  • 12
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论
### 回答1: `orb_publish` 是指在 ROS (Robot Operating System) ,将一个消息发布给指定的主题(topic)。在 ROS ,消息是通过主题(topic)进行传递的。`orb_publish`函数用于将一个特定类型的消息发布到特定的主题,使得订阅该主题的节点能够接收到该消息。 ### 回答2: orb_publish 是一种用于发布消息的操作。"ORB" 是 Object Request Broker 的缩写,是一种间件技术,用于在分布式系统,不同的对象之间进行通信和交互。通过 ORB,对象可以通过发送消息来调用其他对象的方法或获取数据。 orb_publish 则是在 ORB 使用的一个方法或函数,用于将特定的消息发送给订阅了该消息的对象。具体来说,orb_publish 可以将一个消息发布到消息队列,然后被消息队列订阅了该消息的对象所接收。 这种发布-订阅模式使得对象之间的通信更加松散和灵活。发布者(即发布消息的对象)不需要关心消息具体由哪些对象接收,只需要将消息发送出去即可。而订阅者(即订阅了消息的对象)可以自行决定是否接收该消息,并进行相应的处理。这种解耦的设计使得系统更易扩展和维护。 在实际应用orb_publish 可以用于各种需要消息传递的场景,比如分布式计算、实时数据传输等。通过使用 orb_publish,我们可以方便地实现对象之间的消息传递和交互,提高整个系统的灵活性和可扩展性。 ### 回答3: orb_publish是一种基于对象请求代理(Object Request Broker,简称ORB)模式的发布(publish)功能。ORB是一种用于分布式系统对象通信的间件,它允许对象在不同的计算机上进行通信和交互。 在ORB发布是指将一个对象的状态或事件通知给所有对该对象感兴趣的订阅者。orb_publish机制就是ORB提供的一种方式,用于实现发布功能。 使用orb_publish,首先需要定义一个发布者(publisher)。发布者负责创建并维护对象的状态或事件,并将其以特定的格式发布ORB。然后,订阅者(subscriber)可以通过订阅指定的发布者,以接收该发布发布的消息。一旦发布发布了新的消息,ORB会将其发送给所有订阅了该发布者的订阅者。 orb_publish的好处是能够实现对象间的解耦,发布者和订阅者可以独立存在,并且可以动态地添加或移除发布者和订阅者。这种发布/订阅模式可以提高系统的灵活性和可扩展性,方便进行系统的分布和集成。 在实际应用orb_publish可以被广泛应用于各种分布式系统,如企业应用集成(Enterprise Application Integration,EAI)、服务导向架构(Service-Oriented Architecture,SOA)等。通过使用orb_publish,不同的系统或模块可以实现相互之间的通信和协作,实现数据共享和业务流程的集成。 总之,orb_publish是一种基于ORB发布功能,它允许对象在分布式系统进行发布和订阅,实现对象之间的解耦和通信。它具有灵活性和可扩展性,适用于各种分布式系统的应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一叶执念

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值