ros的源码阅读

测试代码,使用xmlrpc与roscore通信

ros的框架是使用rpc与server端通信,server维护topic的publisher,subscriber,param server,serviceServer

import xmlrpclib

server = xmlrpclib.ServerProxy("http://localhost:11311/",verbose=False)

print server.getSystemState('/rosout')

##返回的是 [topic node ] [topic node ] [topic node ] [topic node ]

server

rosmaster/main.py

try:
    logger.info("Starting ROS Master Node")
    #定义master的端口,工作线程,启动
    master = rosmaster.master.Master(port, options.num_workers)
    master.start()

    import time
    while master.ok():
        time.sleep(.1)
except KeyboardInterrupt:
    logger.info("keyboard interrupt, will exit")
finally:
    logger.info("stopping master...")
    master.stop()

rosmaster/master.py

class Master(object):
    
    def __init__(self, port=DEFAULT_MASTER_PORT, num_workers=rosmaster.master_api.NUM_WORKERS):
        self.port = port
        self.num_workers = num_workers
        
    def start(self):
        """
        Start the ROS Master.
        """
        self.handler = None
        self.master_node = None
        self.uri = None

# self.server.register_instance(self.handler)
# 注册handler到xmlrpc,以后每次远程调用的时候,寻找ROSMasterHandler类同名称的函数进行处理返回
        handler = rosmaster.master_api.ROSMasterHandler(self.num_workers)
        master_node = rosgraph.xmlrpc.XmlRpcNode(self.port, handler)
        master_node.start()

        # poll for initialization
        while not master_node.uri:
            time.sleep(0.0001) 

        # save fields
        self.handler = handler
        self.master_node = master_node
        self.uri = master_node.uri

rosmaster/master_api.py

class ROSMasterHandler(object):
    """
    XML-RPC handler for ROS master APIs.
    API routines for the ROS Master Node. The Master Node is a
    superset of the Slave Node and contains additional API methods for
    creating and monitoring a graph of slave nodes.

    By convention, ROS nodes take in caller_id as the first parameter
    of any API call.  The setting of this parameter is rarely done by
    client code as ros::msproxy::MasterProxy automatically inserts
    this parameter (see ros::client::getMaster()).
    """
    
    def __init__(self, num_workers=NUM_WORKERS):
        """ctor."""

        self.uri = None
        self.done = False

        self.thread_pool = rosmaster.threadpool.MarkedThreadPool(num_workers)
        # pub/sub/providers: dict { topicName : [publishers/subscribers names] }
        self.ps_lock = threading.Condition(threading.Lock())

        self.reg_manager = RegistrationManager(self.thread_pool)

        # maintain refs to reg_manager fields
        self.publishers  = self.reg_manager.publishers
        self.subscribers = self.reg_manager.subscribers
        self.services = self.reg_manager.services
        self.param_subscribers = self.reg_manager.param_subscribers
        
        self.topics_types = {} #dict { topicName : type }

        # parameter server dictionary
        self.param_server = rosmaster.paramserver.ParamDictionary(self.reg_manager)

ROSMasterHandler定义的所有函数,也就是xmlrpc服务器处理的函数

542140-20160610170325058-1861022306.png

rosmaster/registrations.py

class RegistrationManager(object):
    """
    Stores registrations for Master.
    
    RegistrationManager is not threadsafe, so access must be externally locked as appropriate
    """

    def __init__(self, thread_pool):
        """
        ctor.
        @param thread_pool: thread pool for queueing tasks
        @type  thread_pool: ThreadPool
        """
        self.nodes = {}
        self.thread_pool = thread_pool

        self.publishers  = Registrations(Registrations.TOPIC_PUBLICATIONS)
        self.subscribers = Registrations(Registrations.TOPIC_SUBSCRIPTIONS)
        self.services = Registrations(Registrations.SERVICE)
        self.param_subscribers = Registrations(Registrations.PARAM_SUBSCRIPTIONS) 

   def _register(self, r, key, caller_id, caller_api, service_api=None):
        # update node information
        node_ref, changed = self._register_node_api(caller_id, caller_api)
        node_ref.add(r.type, key)
        # update pub/sub/service indicies
        if changed:
            self.publishers.unregister_all(caller_id)
            self.subscribers.unregister_all(caller_id)
            self.services.unregister_all(caller_id)
            self.param_subscribers.unregister_all(caller_id)
        r.register(key, caller_id, caller_api, service_api)
        
    def _unregister(self, r, key, caller_id, caller_api, service_api=None):
        node_ref = self.nodes.get(caller_id, None)
        if node_ref != None:
            retval = r.unregister(key, caller_id, caller_api, service_api)
            # check num removed field, if 1, unregister is valid
            if retval[2] == 1:
                node_ref.remove(r.type, key)
            if node_ref.is_empty():
                del self.nodes[caller_id]
        else:
            retval = 1, "[%s] is not a registered node"%caller_id, 0
        return retval

上面的publishers,subscribers,services都是由 Registrations这个类进行管理

542140-20160610170339043-1067396629.png

def registerPublisher(self, caller_id, topic, topic_type, caller_api):
    """
    Register the caller as a publisher the topic.
    @param caller_id: ROS caller id
    @type  caller_id: str
    @param topic: Fully-qualified name of topic to register.
    @type  topic: str
    @param topic_type: Datatype for topic. Must be a
    package-resource name, i.e. the .msg name.
    @type  topic_type: str
    @param caller_api str: ROS caller XML-RPC API URI
    @type  caller_api: str
    @return: (code, statusMessage, subscriberApis).
    List of current subscribers of topic in the form of XMLRPC URIs.
    @rtype: (int, str, [str])
    """
    #NOTE: we need topic_type for getPublishedTopics.
    try:
        self.ps_lock.acquire()
        self.reg_manager.register_publisher(topic, caller_id, caller_api)
        # don't let '*' type squash valid typing
        if topic_type != rosgraph.names.ANYTYPE or not topic in self.topics_types:
            self.topics_types[topic] = topic_type
        pub_uris = self.publishers.get_apis(topic)
        sub_uris = self.subscribers.get_apis(topic)
#通知订阅topic的所有subscriber,回调函数
        self._notify_topic_subscribers(topic, pub_uris, sub_uris)
        mloginfo("+PUB [%s] %s %s",topic, caller_id, caller_api)
        sub_uris = self.subscribers.get_apis(topic)            
    finally:
        self.ps_lock.release()
    return 1, "Registered [%s] as publisher of [%s]"%(caller_id, topic), sub_uris

caller_id 是节点,caller_api http://localhost:53749/

  def _notify(self, registrations, task, key, value, node_apis):
        """
        Generic implementation of callback notification
        @param registrations: Registrations
        @type  registrations: L{Registrations}
        @param task: task to queue
        @type  task: fn
        @param key: registration key
        @type  key: str
        @param value: value to pass to task
        @type  value: Any
        """
        # cache thread_pool for thread safety
        thread_pool = self.thread_pool
        if not thread_pool:
            return
        
        try:            
            for node_api in node_apis:
                # use the api as a marker so that we limit one thread per subscriber
                thread_pool.queue_task(node_api, task, (node_api, key, value))
        except KeyError:
            _logger.warn('subscriber data stale (key [%s], listener [%s]): node API unknown'%(key, s))
        
    def _notify_param_subscribers(self, updates):
        """
        Notify parameter subscribers of new parameter value
        @param updates [([str], str, any)*]: [(subscribers, param_key, param_value)*]
        @param param_value str: parameter value
        """
        # cache thread_pool for thread safety
        thread_pool = self.thread_pool
        if not thread_pool:
            return

        for subscribers, key, value in updates:
            # use the api as a marker so that we limit one thread per subscriber
            for caller_id, caller_api in subscribers:
                self.thread_pool.queue_task(caller_api, self.param_update_task, (caller_id, caller_api, key, value))

client

def init_node(name, argv=None, anonymous=False, log_level=None, disable_rostime=False, disable_rosout=False, disable_signals=False, xmlrpc_port=0, tcpros_port=0):

class MasterProxy(object):
    """
    Convenience wrapper for ROS master API and XML-RPC
    implementation. The Master API methods can be invoked on this
    object and will be forwarded appropriately. Names in arguments
    will be remapped according to current node settings. Provides
    dictionary-like access to parameter server, e.g.::
    
      master[key] = value

    All methods are thread-safe.
    """

rospy 是python的客户端的实现
roscpp 是c++的客户端的实现

ros::NodeHandler构造函数执行会调用ros::start(),接下来ros的框架就起来了。

//init.cpp    
namespace ros{
    void start()
    {

      PollManager::instance()->addPollThreadListener(checkForShutdown);
      XMLRPCManager::instance()->bind("shutdown", shutdownCallback);

      initInternalTimerManager();

      TopicManager::instance()->start();
      ServiceManager::instance()->start();
      ConnectionManager::instance()->start();
      PollManager::instance()->start();
      XMLRPCManager::instance()->start();
    }
};

gdb调试一个listener, talker,service ,client,可以看到每个node都起了好多线程,有专门的log thread, xmlrpc select线程,poll线程

rosgraph 是对底层的master的一个封装,用户一般不直接对他操作

转载于:https://www.cnblogs.com/shhu1993/p/5573925.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,您遇到的问题是关于ROS工作空间中的路径配置问题。具体来说,您的路径'/home/ubuntu/ros_ws/src/ORB_SLAM2/Examples/ROS/ORB_SLAM2/build/devel'在CATKIN_WORKSPACES中,但没有一个.catkin文件。 要解决这个问题,您可以按照以下步骤进行操作: 1. 确保您的路径'/home/ubuntu/ros_ws/src/ORB_SLAM2/Examples/ROS/ORB_SLAM2/build/devel'是正确的,并且确实存在于您的ROS工作空间中。 2. 检查您的CATKIN_WORKSPACES环境变量是否正确设置。您可以通过运行以下命令来检查: ```shell echo $CATKIN_WORKSPACES ``` 如果输出中没有包含您的路径'/home/ubuntu/ros_ws/src/ORB_SLAM2/Examples/ROS/ORB_SLAM2/build/devel',则需要将其添加到环境变量中。您可以使用以下命令将其添加到环境变量中: ```shell export CATKIN_WORKSPACES=$CATKIN_WORKSPACES:/home/ubuntu/ros_ws/src/ORB_SLAM2/Examples/ROS/ORB_SLAM2/build/devel ``` 然后,再次运行echo命令来确认路径已经添加到环境变量中。 3. 确保您的路径中存在一个名为.catkin的文件。如果不存在,请在路径中创建一个名为.catkin的文件。您可以使用以下命令创建该文件: ```shell touch /home/ubuntu/ros_ws/src/ORB_SLAM2/Examples/ROS/ORB_SLAM2/build/devel/.catkin ``` 然后,再次运行您的程序,应该不再出现该错误。 请注意,以上步骤是基于提供的引用内容进行的推测。如果您的具体情况有所不同,请提供更多详细信息以便我能够给出更准确的答案。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值