美文网首页
ROS-I simple_message 源码分析:Messag

ROS-I simple_message 源码分析:Messag

作者: play_robot | 来源:发表于2019-03-21 15:26 被阅读0次

    MessageManager通过它的通信连接接收simple message。而后基于收到的message类型调用相应的回调函数,回调函数则执行相应的操作,以及根据需要作出消息应答。

    MessageManager有两种工作模式:spin()spinOnce()
    spin的执行是阻塞式的,而spinOnce是执行一次单独的操作。因此,在spinOnce模式下,程序可以同时干其它事情,但是要确保执行spinOnce的频率足够高,这样不至于丢失通信数据。

    namespace industrial
    {
    namespace message_manager
    {
    
    class MessageManager
    {
    
    public:
    
      MessageManager();
      ~MessageManager();
    
      bool init(industrial::smpl_msg_connection::SmplMsgConnection* connection);
      bool init(industrial::smpl_msg_connection::SmplMsgConnection* connection,
                industrial::comms_fault_handler::CommsFaultHandler* fault_handler);
    
      void spinOnce();
      void spin();
    
      bool add(industrial::message_handler::MessageHandler* handler, bool allow_replace = false);
    
      unsigned int getNumHandlers()
      {
        return this->num_handlers_;
      }
    
      unsigned int getMaxNumHandlers()
      {
        return this->MAX_NUM_HANDLERS;
      }
    
      industrial::comms_fault_handler::CommsFaultHandler* getCommsFaultHandler()
      {
        return this->comms_hndlr_;
      }
    
      void setCommsFaultHandler(industrial::comms_fault_handler::CommsFaultHandler* handler)
      {
        this->comms_hndlr_ = handler;
      }
    
    
    private:
    
      static const unsigned int MAX_NUM_HANDLERS = 64;
      industrial::message_handler::MessageHandler* handlers_[MAX_NUM_HANDLERS];
      industrial::smpl_msg_connection::SmplMsgConnection* connection_;
      industrial::ping_handler::PingHandler ping_hndlr_;
      industrial::simple_comms_fault_handler::SimpleCommsFaultHandler def_comms_hndlr_;
      industrial::comms_fault_handler::CommsFaultHandler* comms_hndlr_;
      unsigned int num_handlers_;
    
      industrial::message_handler::MessageHandler* getHandler(int msg_type);
      int getHandlerIdx(int msg_type);
    
      industrial::simple_comms_fault_handler::SimpleCommsFaultHandler& getDefaultCommsFaultHandler()
      {
        return this->def_comms_hndlr_;
      }
    
      industrial::ping_handler::PingHandler& getPingHandler()
      {
        return this->ping_hndlr_;
      }
      ;
    
      void setConnection(industrial::smpl_msg_connection::SmplMsgConnection* connection)
      {
        this->connection_ = connection;
      }
      ;
    
      industrial::smpl_msg_connection::SmplMsgConnection* getConnection()
      {
        return this->connection_;
      }
      ;
    
      void setNumHandlers(unsigned int num_handlers)
      {
        this->num_handlers_ = num_handlers;
      }
      ;
    
    };
    
    } // namespace industrial
    } // namespace message_manager
    

    先来看一下它的私有成员:

    类型 变量符号 含义
    int MAX_NUM_HANDLERS 消息处理器的最大数目
    int num_handlers_ 消息处理器的实际数目
    MessageHandler* handlers_[MAX_NUM_HANDLERS] 存放消息处理器的指针数组
    SmplMsgConnection* connection_ 通信使用的连接
    PingHandler ping_hndlr_ ping消息处理器
    SimpleCommsFaultHandler def_comms_hndlr_ 默认的通信错误处理器
    CommsFaultHandler* comms_hndlr_ 用户指定的通信错误处理器

    在使用MessageManager时,外部需要先初始化好connection,然后传入init以初始化MessageManager使用的连接和错误处理器,此外还将初始化ping_hndlr_对象,并调用add将ping_hndlr_存放到handlers_数组中,保存的目的就在于当遇到ping message时,MessageManager就会调用PingHandler来处理该消息。

    下面分析spinOnce代码:

    void MessageManager::spinOnce()
    {
      SimpleMessage msg;
      MessageHandler* handler = NULL;
    
      if(!this->getConnection()->isConnected())
      {
        this->getCommsFaultHandler()->connectionFailCB();
      }
    
      if (this->getConnection()->receiveMsg(msg))
      {
        LOG_COMM("Message received");
        handler = this->getHandler(msg.getMessageType());
    
        if (NULL != handler)
        {
          LOG_DEBUG("Executing handler callback for message type: %d", handler->getMsgType());
          handler->callback(msg);
        }
        else
        {
          if (CommTypes::SERVICE_REQUEST == msg.getCommType())
          {
            simple_message::SimpleMessage fail;
            fail.init(msg.getMessageType(), CommTypes::SERVICE_REPLY, ReplyTypes::FAILURE);
            this->getConnection()->sendMsg(fail);
            LOG_WARN("Unhandled message type encounters, sending failure reply");
          }
          LOG_ERROR("Message callback for message type: %d, not executed", msg.getMessageType());
        }
      }
      else
      {
        LOG_ERROR("Failed to receive incoming message");
        this->getCommsFaultHandler()->sendFailCB();
      }
    }
    

    进入spinOnce后,首先会检查是否处于连接状态,如果连接断开则触发通信错误处理器的连接失败回调函数connectionFailCB。接着将尝试接收一条SimpleMessage消息,如果接收到消息,则根据消息类型寻找能处理该消息的处理器handler,找到后则触发处理的回调函数callback对接收到的消息进行处理。

    对于spin方法,它是基于spinOnce实现的,进入该方法后,程序将进入内部的死循环,持续调用spinOnce:

    void MessageManager::spin()
    {
      LOG_INFO("Entering message manager spin loop");
    #ifdef ROS
      while (ros::ok())
    #else
      while (true)
    #endif
      {
        this->spinOnce();
    
        // Throttle loop speed if waiting for a re-connection
        if (!this->getConnection()->isConnected())
          mySleep(5);
      }
    }
    

    MessageManager就分析到这里,后面再举例分析在更上层的代码中是如何使用它的。

    相关文章

      网友评论

          本文标题:ROS-I simple_message 源码分析:Messag

          本文链接:https://www.haomeiwen.com/subject/lllqvqtx.html