思考问题:

1. 如何实现传感器数据的融合,或者说时间同步? 比如里程计读数和雷达数据融合?

void SlamGMapping::startLiveSlam()
{entropy_publisher_ = private_nh_.advertise<std_msgs::Float64>("entropy", 1, true);sst_ = node_.advertise<nav_msgs::OccupancyGrid>("map", 1, true);sstm_ = node_.advertise<nav_msgs::MapMetaData>("map_metadata", 1, true);ss_ = node_.advertiseService("dynamic_map", &SlamGMapping::mapCallback, this);scan_filter_sub_ = new message_filters::Subscriber<sensor_msgs::LaserScan>(node_, "scan", 5);scan_filter_ = new tf::MessageFilter<sensor_msgs::LaserScan>(*scan_filter_sub_, tf_, odom_frame_, 5);scan_filter_->registerCallback(boost::bind(&SlamGMapping::laserCallback, this, _1));transform_thread_ = new boost::thread(boost::bind(&SlamGMapping::publishLoop, this, transform_publish_period_));
}

ROS中message_filters 和 tf::MessageFilter 需要关注一下。

  message_filters is a utility library for use with roscpp and rospy. It collects commonly used message "filtering" algorithms into a common space. A message filter is defined as something which a message arrives into and may or may not be spit back out of at a later point in time.

  An example is the time synchronizer, which takes in messages of different types from multiple sources, and outputs them only if it has received a message on each of those sources with the same timestamp.

  以下为MessageFilter泛型类执行的基本流程。

 /*** \brief Connect this filter's input to another filter's output.  If this filter is already connected, disconnects first.*/template<class F>  void connectInput(F& f){message_connection_.disconnect();message_connection_ = f.registerCallback(&MessageFilter::incomingMessage, this);}

 void incomingMessage(const ros::MessageEvent<M const>& evt){add(evt);}

  /*** \brief Manually add a message into this filter.* \note If the message (or any other messages in the queue) are immediately transformable this will immediately call through to the output callback, possibly* multiple times*/void add(const MConstPtr& message){boost::shared_ptr<std::map<std::string, std::string> > header(new std::map<std::string, std::string>);(*header)["callerid"] = "unknown";add(MEvent(message, header, ros::Time::now()));}

  1 void add(const MEvent& evt)
  2   {
  3     if (target_frames_.empty())
  4     {
  5       return;
  6     }
  7
  8     namespace mt = ros::message_traits;
  9     const MConstPtr& message = evt.getMessage();
 10     std::string frame_id = stripSlash(mt::FrameId<M>::value(*message));
 11     ros::Time stamp = mt::TimeStamp<M>::value(*message);
 12
 13     if (frame_id.empty())
 14     {
 15       messageDropped(evt, filter_failure_reasons::EmptyFrameID);
 16       return;
 17     }
 18
 19     // iterate through the target frames and add requests for each of them
 20     MessageInfo info;
 21     info.handles.reserve(expected_success_count_);
 22     {
 23       V_string target_frames_copy;
 24       // Copy target_frames_ to avoid deadlock from #79
 25       {
 26         boost::mutex::scoped_lock frames_lock(target_frames_mutex_);
 27         target_frames_copy = target_frames_;
 28       }
 29
 30       V_string::iterator it = target_frames_copy.begin();
 31       V_string::iterator end = target_frames_copy.end();
 32       for (; it != end; ++it)
 33       {
 34         const std::string& target_frame = *it;
 35         tf2::TransformableRequestHandle handle = bc_.addTransformableRequest(callback_handle_, target_frame, frame_id, stamp);
 36         if (handle == 0xffffffffffffffffULL) // never transformable
 37         {
 38           messageDropped(evt, filter_failure_reasons::OutTheBack);
 39           return;
 40         }
 41         else if (handle == 0)
 42         {
 43           ++info.success_count;
 44         }
 45         else
 46         {
 47           info.handles.push_back(handle);
 48         }
 49
 50         if (!time_tolerance_.isZero())
 51         {
 52           handle = bc_.addTransformableRequest(callback_handle_, target_frame, frame_id, stamp + time_tolerance_);
 53           if (handle == 0xffffffffffffffffULL) // never transformable
 54           {
 55             messageDropped(evt, filter_failure_reasons::OutTheBack);
 56             return;
 57           }
 58           else if (handle == 0)
 59           {
 60             ++info.success_count;
 61           }
 62           else
 63           {
 64             info.handles.push_back(handle);
 65           }
 66         }
 67       }
 68     }
 69
 70
 71     // We can transform already
 72     if (info.success_count == expected_success_count_)
 73     {
 74       messageReady(evt);
 75     }
 76     else
 77     {
 78       // If this message is about to push us past our queue size, erase the oldest message
 79       if (queue_size_ != 0 && message_count_ + 1 > queue_size_)
 80       {
 81         // While we're using the reference keep a shared lock on the messages.
 82         boost::shared_lock< boost::shared_mutex > shared_lock(messages_mutex_);
 83
 84         ++dropped_message_count_;
 85         const MessageInfo& front = messages_.front();
 86         TF2_ROS_MESSAGEFILTER_DEBUG("Removed oldest message because buffer is full, count now %d (frame_id=%s, stamp=%f)", message_count_,
 87                                 (mt::FrameId<M>::value(*front.event.getMessage())).c_str(), mt::TimeStamp<M>::value(*front.event.getMessage()).toSec());
 88
 89         V_TransformableRequestHandle::const_iterator it = front.handles.begin();
 90         V_TransformableRequestHandle::const_iterator end = front.handles.end();
 91         for (; it != end; ++it)
 92         {
 93           bc_.cancelTransformableRequest(*it);
 94         }
 95
 96         messageDropped(front.event, filter_failure_reasons::Unknown);
 97         // Unlock the shared lock and get a unique lock. Upgradeable lock is used in transformable.
 98         // There can only be one upgrade lock. It's important the cancelTransformableRequest not deadlock with transformable.
 99         // They both require the transformable_requests_mutex_ in BufferCore.
100         shared_lock.unlock();
101         // There is a very slight race condition if an older message arrives in this gap.
102         boost::unique_lock< boost::shared_mutex > unique_lock(messages_mutex_);
103         messages_.pop_front();
104          --message_count_;
105       }
106
107       // Add the message to our list
108       info.event = evt;
109       // Lock access to the messages_ before modifying them.
110       boost::unique_lock< boost::shared_mutex > unique_lock(messages_mutex_);
111       messages_.push_back(info);
112       ++message_count_;
113     }
114
115     TF2_ROS_MESSAGEFILTER_DEBUG("Added message in frame %s at time %.3f, count now %d", frame_id.c_str(), stamp.toSec(), message_count_);
116
117     ++incoming_message_count_;
118   }

完整的类代码:http://docs.ros.org/api/tf/html/c++/message__filter_8h_source.html

 1 /*2  * Copyright (c) 2008, Willow Garage, Inc.3  * All rights reserved.4  *5  * Redistribution and use in source and binary forms, with or without6  * modification, are permitted provided that the following conditions are met:7  *8  *     * Redistributions of source code must retain the above copyright9  *       notice, this list of conditions and the following disclaimer.10  *     * Redistributions in binary form must reproduce the above copyright11  *       notice, this list of conditions and the following disclaimer in the12  *       documentation and/or other materials provided with the distribution.13  *     * Neither the name of the Willow Garage, Inc. nor the names of its14  *       contributors may be used to endorse or promote products derived from15  *       this software without specific prior written permission.16  *17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE27  * POSSIBILITY OF SUCH DAMAGE.28  */29 32 #ifndef TF_MESSAGE_FILTER_H33 #define TF_MESSAGE_FILTER_H34 35 #include <ros/ros.h>36 #include <tf/transform_listener.h>37 #include <tf/tfMessage.h>38 39 #include <string>40 #include <list>41 #include <vector>42 #include <boost/function.hpp>43 #include <boost/bind.hpp>44 #include <boost/shared_ptr.hpp>45 #include <boost/weak_ptr.hpp>46 #include <boost/thread.hpp>47 #include <boost/signals2.hpp>48 49 #include <ros/callback_queue.h>50 51 #include <message_filters/connection.h>52 #include <message_filters/simple_filter.h>53 54 #define TF_MESSAGEFILTER_DEBUG(fmt, ...) \55   ROS_DEBUG_NAMED("message_filter", "MessageFilter [target=%s]: " fmt, getTargetFramesString().c_str(), __VA_ARGS__)56 57 #define TF_MESSAGEFILTER_WARN(fmt, ...) \58   ROS_WARN_NAMED("message_filter", "MessageFilter [target=%s]: " fmt, getTargetFramesString().c_str(), __VA_ARGS__)59 60 namespace tf61 {62 63 namespace filter_failure_reasons64 {65 enum FilterFailureReason66 {68   Unknown,70   OutTheBack,72   EmptyFrameID,73 };74 }75 typedef filter_failure_reasons::FilterFailureReason FilterFailureReason;76 77 class MessageFilterBase78 {79 public:80   virtual ~MessageFilterBase(){}81   virtual void clear() = 0;82   virtual void setTargetFrame(const std::string& target_frame) = 0;83   virtual void setTargetFrames(const std::vector<std::string>& target_frames) = 0;84   virtual void setTolerance(const ros::Duration& tolerance) = 0;85   virtual void setQueueSize( uint32_t new_queue_size ) = 0;86   virtual uint32_t getQueueSize() = 0;87 };88 105 template<class M>106 class MessageFilter : public MessageFilterBase, public message_filters::SimpleFilter<M>107 {108 public:109   typedef boost::shared_ptr<M const> MConstPtr;110   typedef ros::MessageEvent<M const> MEvent;111   typedef boost::function<void(const MConstPtr&, FilterFailureReason)> FailureCallback;112   typedef boost::signals2::signal<void(const MConstPtr&, FilterFailureReason)> FailureSignal;113 123   MessageFilter(Transformer& tf, const std::string& target_frame, uint32_t queue_size, ros::NodeHandle nh = ros::NodeHandle(), ros::Duration max_rate = ros::Duration(0.01))124   : tf_(tf)125   , nh_(nh)126   , max_rate_(max_rate)127   , queue_size_(queue_size)128   {129     init();130 131     setTargetFrame(target_frame);132   }133 144   template<class F>145   MessageFilter(F& f, Transformer& tf, const std::string& target_frame, uint32_t queue_size, ros::NodeHandle nh = ros::NodeHandle(), ros::Duration max_rate = ros::Duration(0.01))146   : tf_(tf)147   , nh_(nh)148   , max_rate_(max_rate)149   , queue_size_(queue_size)150   {151     init();152 153     setTargetFrame(target_frame);154 155     connectInput(f);156   }157 161   template<class F>162   void connectInput(F& f)163   {164     message_connection_.disconnect();165     message_connection_ = f.registerCallback(&MessageFilter::incomingMessage, this);166   }167 171   ~MessageFilter()172   {173     // Explicitly stop callbacks; they could execute after we're destroyed174     max_rate_timer_.stop();175     message_connection_.disconnect();176     tf_.removeTransformsChangedListener(tf_connection_);177 178     clear();179 180     TF_MESSAGEFILTER_DEBUG("Successful Transforms: %llu, Failed Transforms: %llu, Discarded due to age: %llu, Transform messages received: %llu, Messages received: %llu, Total dropped: %llu",181                            (long long unsigned int)successful_transform_count_, (long long unsigned int)failed_transform_count_, 182                            (long long unsigned int)failed_out_the_back_count_, (long long unsigned int)transform_message_count_, 183                            (long long unsigned int)incoming_message_count_, (long long unsigned int)dropped_message_count_);184 185   }186 190   void setTargetFrame(const std::string& target_frame)191   {192     std::vector<std::string> frames;193     frames.push_back(target_frame);194     setTargetFrames(frames);195   }196 200   void setTargetFrames(const std::vector<std::string>& target_frames)201   {202     boost::mutex::scoped_lock list_lock(messages_mutex_);203     boost::mutex::scoped_lock string_lock(target_frames_string_mutex_);204 205     target_frames_ = target_frames;206 207     std::stringstream ss;208     for (std::vector<std::string>::iterator it = target_frames_.begin(); it != target_frames_.end(); ++it)209     {210       ss << *it << " ";211     }212     target_frames_string_ = ss.str();213   }217   std::string getTargetFramesString()218   {219     boost::mutex::scoped_lock lock(target_frames_string_mutex_);220     return target_frames_string_;221   };222 226   void setTolerance(const ros::Duration& tolerance)227   {228     time_tolerance_ = tolerance;229   }230 234   void clear()235   {236     boost::mutex::scoped_lock lock(messages_mutex_);237 238     TF_MESSAGEFILTER_DEBUG("%s", "Cleared");239 240     messages_.clear();241     message_count_ = 0;242 243     warned_about_unresolved_name_ = false;244     warned_about_empty_frame_id_ = false;245   }246 247   void add(const MEvent& evt)248   {249     boost::mutex::scoped_lock lock(messages_mutex_);250 251     testMessages();252 253     if (!testMessage(evt))254     {255       // If this message is about to push us past our queue size, erase the oldest message256       if (queue_size_ != 0 && message_count_ + 1 > queue_size_)257       {258         ++dropped_message_count_;259         const MEvent& front = messages_.front();260         TF_MESSAGEFILTER_DEBUG(261               "Removed oldest message because buffer is full, count now %d (frame_id=%s, stamp=%f)",262               message_count_,263               ros::message_traits::FrameId<M>::value(*front.getMessage()).c_str(),264               ros::message_traits::TimeStamp<M>::value(*front.getMessage()).toSec());265         signalFailure(messages_.front(), filter_failure_reasons::Unknown);266 267         messages_.pop_front();268         --message_count_;269       }270 271       // Add the message to our list272       messages_.push_back(evt);273       ++message_count_;274     }275 276     TF_MESSAGEFILTER_DEBUG(277           "Added message in frame %s at time %.3f, count now %d",278           ros::message_traits::FrameId<M>::value(*evt.getMessage()).c_str(),279           ros::message_traits::TimeStamp<M>::value(*evt.getMessage()).toSec(),280           message_count_);281 282     ++incoming_message_count_;283   }284 290   void add(const MConstPtr& message)291   {292     293     boost::shared_ptr<std::map<std::string, std::string> > header(new std::map<std::string, std::string>);294     (*header)["callerid"] = "unknown";295     add(MEvent(message, header, ros::Time::now()));296   }297 302   message_filters::Connection registerFailureCallback(const FailureCallback& callback)303   {304     boost::mutex::scoped_lock lock(failure_signal_mutex_);305     return message_filters::Connection(boost::bind(&MessageFilter::disconnectFailure, this, _1), failure_signal_.connect(callback));306   }307 308   virtual void setQueueSize( uint32_t new_queue_size )309   {310     queue_size_ = new_queue_size;311   }312 313   virtual uint32_t getQueueSize()314   {315     return queue_size_;316   }317 318 private:319 320   void init()321   {322     message_count_ = 0;323     new_transforms_ = false;324     successful_transform_count_ = 0;325     failed_transform_count_ = 0;326     failed_out_the_back_count_ = 0;327     transform_message_count_ = 0;328     incoming_message_count_ = 0;329     dropped_message_count_ = 0;330     time_tolerance_ = ros::Duration(0.0);331     warned_about_unresolved_name_ = false;332     warned_about_empty_frame_id_ = false;333 334     tf_connection_ = tf_.addTransformsChangedListener(boost::bind(&MessageFilter::transformsChanged, this));335 336     max_rate_timer_ = nh_.createTimer(max_rate_, &MessageFilter::maxRateTimerCallback, this);337   }338 339   typedef std::list<MEvent> L_Event;340 341   bool testMessage(const MEvent& evt)342   {343     const MConstPtr& message = evt.getMessage();344     std::string callerid = evt.getPublisherName();345     std::string frame_id = ros::message_traits::FrameId<M>::value(*message);346     ros::Time stamp = ros::message_traits::TimeStamp<M>::value(*message);347 348     //Throw out messages which have an empty frame_id349     if (frame_id.empty())350     {351       if (!warned_about_empty_frame_id_)352       {353         warned_about_empty_frame_id_ = true;354         TF_MESSAGEFILTER_WARN("Discarding message from [%s] due to empty frame_id.  This message will only print once.", callerid.c_str());355       }356       signalFailure(evt, filter_failure_reasons::EmptyFrameID);357       return true;358     }359 360 361     //Throw out messages which are too old363     for (std::vector<std::string>::iterator target_it = target_frames_.begin(); target_it != target_frames_.end(); ++target_it)364     {365       const std::string& target_frame = *target_it;366 367       if (target_frame != frame_id && stamp != ros::Time(0))368       {369         ros::Time latest_transform_time ;370 371         tf_.getLatestCommonTime(frame_id, target_frame, latest_transform_time, 0) ;372         373         if (stamp + tf_.getCacheLength() < latest_transform_time)374         {375           ++failed_out_the_back_count_;376           ++dropped_message_count_;377           TF_MESSAGEFILTER_DEBUG(378                 "Discarding Message, in frame %s, Out of the back of Cache Time "379                 "(stamp: %.3f + cache_length: %.3f < latest_transform_time %.3f. "380                 "Message Count now: %d",381                 ros::message_traits::FrameId<M>::value(*message).c_str(),382                 ros::message_traits::TimeStamp<M>::value(*message).toSec(),383                 tf_.getCacheLength().toSec(), latest_transform_time.toSec(), message_count_);384 385           last_out_the_back_stamp_ = stamp;386           last_out_the_back_frame_ = frame_id;387 388           signalFailure(evt, filter_failure_reasons::OutTheBack);389           return true;390         }391       }392 393     }394 395     bool ready = !target_frames_.empty();396     for (std::vector<std::string>::iterator target_it = target_frames_.begin(); ready && target_it != target_frames_.end(); ++target_it)397     {398       std::string& target_frame = *target_it;399       if (time_tolerance_ != ros::Duration(0.0))400       {401         ready = ready && (tf_.canTransform(target_frame, frame_id, stamp) &&402                           tf_.canTransform(target_frame, frame_id, stamp + time_tolerance_) );403       }404       else405       {406         ready = ready && tf_.canTransform(target_frame, frame_id, stamp);407       }408     }409 410     if (ready)411     {412       TF_MESSAGEFILTER_DEBUG("Message ready in frame %s at time %.3f, count now %d", frame_id.c_str(), stamp.toSec(), message_count_);413 414       ++successful_transform_count_;415 416       this->signalMessage(evt);417     }418     else419     {420       ++failed_transform_count_;421     }422 423     return ready;424   }425 426   void testMessages()427   {428     if (!messages_.empty() && getTargetFramesString() == " ")429     {430       ROS_WARN_NAMED("message_notifier", "MessageFilter [target=%s]: empty target frame", getTargetFramesString().c_str());431     }432 433     int i = 0;434 435     typename L_Event::iterator it = messages_.begin();436     for (; it != messages_.end(); ++i)437     {438       MEvent& evt = *it;439 440       if (testMessage(evt))441       {442         --message_count_;443         it = messages_.erase(it);444       }445       else446       {447         ++it;448       }449     }450   }451 452   void maxRateTimerCallback(const ros::TimerEvent&)453   {454     boost::mutex::scoped_lock list_lock(messages_mutex_);455     if (new_transforms_)456     {457       testMessages();458       new_transforms_ = false;459     }460 461     checkFailures();462   }463 467   void incomingMessage(const ros::MessageEvent<M const>& evt)468   {469     add(evt);470   }471 472   void transformsChanged()473   {474     new_transforms_ = true;475 476     ++transform_message_count_;477   }478 479   void checkFailures()480   {481     if (next_failure_warning_.isZero())482     {483       next_failure_warning_ = ros::Time::now() + ros::Duration(15);484     }485 486     if (ros::Time::now() >= next_failure_warning_)487     {488       if (incoming_message_count_ - message_count_ == 0)489       {490         return;491       }492 493       double dropped_pct = (double)dropped_message_count_ / (double)(incoming_message_count_ - message_count_);494       if (dropped_pct > 0.95)495       {496         TF_MESSAGEFILTER_WARN("Dropped %.2f%% of messages so far. Please turn the [%s.message_notifier] rosconsole logger to DEBUG for more information.", dropped_pct*100, ROSCONSOLE_DEFAULT_NAME);497         next_failure_warning_ = ros::Time::now() + ros::Duration(60);498 499         if ((double)failed_out_the_back_count_ / (double)dropped_message_count_ > 0.5)500         {501           TF_MESSAGEFILTER_WARN("  The majority of dropped messages were due to messages growing older than the TF cache time.  The last message's timestamp was: %f, and the last frame_id was: %s", last_out_the_back_stamp_.toSec(), last_out_the_back_frame_.c_str());502         }503       }504     }505   }506 507   void disconnectFailure(const message_filters::Connection& c)508   {509     boost::mutex::scoped_lock lock(failure_signal_mutex_);510     c.getBoostConnection().disconnect();511   }512 513   void signalFailure(const MEvent& evt, FilterFailureReason reason)514   {515     boost::mutex::scoped_lock lock(failure_signal_mutex_);516     failure_signal_(evt.getMessage(), reason);517   }518 519   Transformer& tf_; 520   ros::NodeHandle nh_; 521   ros::Duration max_rate_;522   ros::Timer max_rate_timer_;523   std::vector<std::string> target_frames_; 524   std::string target_frames_string_;525   boost::mutex target_frames_string_mutex_;526   uint32_t queue_size_; 527 528   L_Event messages_; 529   uint32_t message_count_; 530   boost::mutex messages_mutex_; 531 532   bool new_messages_; 533   volatile bool new_transforms_; 534 535   bool warned_about_unresolved_name_;536   bool warned_about_empty_frame_id_;537 538   uint64_t successful_transform_count_;539   uint64_t failed_transform_count_;540   uint64_t failed_out_the_back_count_;541   uint64_t transform_message_count_;542   uint64_t incoming_message_count_;543   uint64_t dropped_message_count_;544 545   ros::Time last_out_the_back_stamp_;546   std::string last_out_the_back_frame_;547 548   ros::Time next_failure_warning_;549 550   ros::Duration time_tolerance_; 551 552   boost::signals2::connection tf_connection_;553   message_filters::Connection message_connection_;554 555   FailureSignal failure_signal_;556   boost::mutex failure_signal_mutex_;557 };558 559 560 } // namespace tf561 562 #endif563 

TF_MESSAGE_FILTER


 1 bool
 2 Buffer::canTransform(const std::string& target_frame, const std::string& source_frame,
 3                      const ros::Time& time, const ros::Duration timeout, std::string* errstr) const
 4 {
 5   if (!checkAndErrorDedicatedThreadPresent(errstr))
 6     return false;
 7
 8   // poll for transform if timeout is set
 9   ros::Time start_time = now_fallback_to_wall();
10   while (now_fallback_to_wall() < start_time + timeout &&
11          !canTransform(target_frame, source_frame, time) &&
12          (now_fallback_to_wall()+ros::Duration(3.0) >= start_time) &&  //don't wait when we detect a bag loop
13          (ros::ok() || !ros::isInitialized())) // Make sure we haven't been stopped (won't work for pytf)
14     {
15       sleep_fallback_to_wall(ros::Duration(0.01));
16     }
17   bool retval = canTransform(target_frame, source_frame, time, errstr);
18   conditionally_append_timeout_info(errstr, start_time, timeout);
19   return retval;
20 }
21
22 ros::Time now_fallback_to_wall()
23 {
24   try
25   {
26     return ros::Time::now();
27   }
28   catch (ros::TimeNotInitializedException ex)
29   {
30     ros::WallTime wt = ros::WallTime::now();
31     return ros::Time(wt.sec, wt.nsec);
32   }
33 }

#include "tf2_ros/buffer.h"

2.ROS中的消息发布与订阅机制为啥不需要线程锁?

[ROS]一些传感器数据读取融合问题的思考相关推荐

  1. 四旋翼无人机仿真之hector_quadrotor无人机(ROS + Gazebo)(三)传感器数据读取与复现(IMU、GPS)

    系列文章目录 文章1:四旋翼无人机仿真之hector_quadrotor无人机(ROS + Gazebo) 文章2:四旋翼无人机仿真之hector_quadrotor(二)键盘teleop_twist ...

  2. 匿名四轴【 任务一(1000Hz)惯性传感器数据读取一】

    上一篇说了传感器数据读取,接下来来看惯性传感器数据读取 //我们来看这个函数现在到了第二部分惯性传感器数据读取 u32 test_dT_1000hz[3],test_rT[6]; static voi ...

  3. 德国海曼HTPA 32x32d热成像传感器代替MLX90640之传感器数据读取和计算

    传感器数据读取和计算 之前的文章我们简单介绍了热成像传感器德国海曼的HTPA 32x32d的EEPROM数据读取和解析,本文主要进一步介绍传感器数据读取,最终通过五大步计算和校准得到我们想要的32x3 ...

  4. 什么是陀螺仪的dr算法_陀螺仪与加速传感器数据的融合算法解析

    1.加速度计数据处理 为了实现代步车平平衡和运动控制,首先应该得到足够精确机器人车身倾角信息.根据两轮处自平衡车的应用环境,一般使用加速度器和陀螺仪两种传感器来采集代步车的姿态信息. 加速度计可能测量 ...

  5. HK-2010/3三通道脉象传感器/脉象传感器数据读取

    目录 一.传感器 二.数据 三.数据读取 1 Python读取 2 Matlab读取 一.传感器 HK-2010/3是一款功能强大的传感器模组,它结合了三通道脉搏波

  6. STM32F4对使用rs485通信的传感器数据读取

    一.目的 最近在基于stm32f407的项目中应用了很多使用RS485进行通信的传感器设备,连接成485组网后需要进行数据的读写,在这里将一些过程写下,希望有需要的人能有个借鉴. 二.传感器说明 本次 ...

  7. (5)泪目写下唯一成功之MQ2传感器数据读取

    ----哦,搞了半天原来这么回事----- (1)首先说一下baseoverlay(官方定义的引脚名称): 参考下面的图片和https://pynq.readthedocs.io/en/latest/ ...

  8. STM32CubeIDE自平衡小车教程7.MPU6050传感器数据读取

    MPU6050简介: MPU6050是InvenSense公司推出的全球首款整合性6轴运动处理组件,内带3轴陀螺仪和3轴加速度传感器,并且含有一个第二IIC接口,可用于连接外部磁力传感器. 那如何通过 ...

  9. 动手学无人驾驶(5):多传感器数据融合

    本系列的前4篇文章主要介绍了深度学习技术在无人驾驶环境感知中的应用,包括交通标志识别,图像与点云3D目标检测.关于环境感知部分的介绍本系列暂且告一段落,后续如有需要再进行补充. 现在我们开启新的篇章, ...

  10. WebServer应用示例2:Siri语音识别读取传感器数据 | ESP32轻松学(Arduino版)

    本系列历史文章目录: ESP32 概述与 Arduino 软件准备 ESP32与掌控板IO接口编程入门 蓝牙翻页笔(PPT 控制器) B 站粉丝计数器 Siri 语音识别控制 LED 灯 Siri 语 ...

最新文章

  1. 机器学习“七宗罪”:影响可信度的七个常见错误
  2. WKWebView中经常用到的操作
  3. inotify 文件系统监控
  4. Java 里的 abstract 和 final 关键字
  5. java 23种设计模式 深入理解
  6. android webview简单使用,android WebView 简单使用Demo
  7. ZBLOG简单的导航网站主题 支持内页详情目录模板
  8. 解决 favicon.ico 404 (Not Found)
  9. web前端开发 —— 一个对联效果
  10. HALCON 21.11:深度学习笔记---分类(10)
  11. 面试必问的 Linux 命令帮你整理好啦 (下)
  12. 面试准备JSONP(一)
  13. html货币相关符号
  14. megacli通过盘符定位物理盘_Megaraid 磁盘定位
  15. Ci522 13.56MHz非接触式读写器芯片--Si522 Lowcost版本
  16. 机动车污染排放检验信息系统信息化建设目标及规范
  17. 360浏览器打不开html5文件,360浏览器打不开oa_打不开360浏览器
  18. Python基础语法知识3
  19. 数值分析18 - 通过直接方法得到函数积分近似 数值方法(左、右、中、梯形矩形积分公式、Simpson积分公式)
  20. 5个球放入3个箱子_排列组合问题,把5个相同的球放到三个相同的盒子里,要求每个盒子都有球,则不同的放球方法是多少?...

热门文章

  1. numpy的squeeze函数和expand_dims函数
  2. 不可重复读,虚读和脏读的区别
  3. 弹出visual studio 实时调试器解决
  4. 【python】pycharts画关联图
  5. Sue的小球 [费用提前计算]
  6. python安装出错0x80072ee7_python3.6.4安装错误0x80072efd
  7. commit翻译中文_commit的意思在线翻译,解释commit中文英文含义,短语词组,音标读音,例句,词源,同义词【澳典网ODict.Net】...
  8. 请仔细核对自己的信息
  9. 我的编程之路点滴记录(二)
  10. 标签助手(TagHelper)