class Orocos::ROS::NameService
A name service implementation that allows to enumerate all ROS nodes
Attributes
The Utilrb::ThreadPool object that handles the asynchronous update of the ROS node graph @return [Utilrb::ThreadPool]
The time of the last update to ros_graph. This is the time at which the XMLRPC request has been made @return [Time]
Public Class Methods
# File lib/orocos/ros/name_service.rb, line 112 def initialize(uri = ROS.default_ros_master_uri, caller_id = ROS.caller_id, options = Hash.new) options = Kernel.validate_options options, :poll_period => 1 @uri = uri @caller_id = caller_id @ros_graph = NodeGraph.new @mutex = Mutex.new @ros_master_sync = Mutex.new @updated_graph_signal = ConditionVariable.new @update_time = Time.at(0) @poll_period = options[:poll_period] super() @ros_master = ROSMaster.new(uri, caller_id) @thread_pool = Utilrb::ThreadPool.new(0, 2) poll_system_state end
Public Instance Methods
# File lib/orocos/ros/name_service.rb, line 131 def ==(other) other.class == self.class && other.uri == self.uri end
# File lib/orocos/ros/name_service.rb, line 165 def done_system_state(result, exception) time, graph = *result update_system_state(time, graph, exception) sleep(poll_period) poll_system_state end
Returns the Topic object that matches the given topic name. If that topic has more than one publisher (yuk), it picks the first one.
@return [Topic]
# File lib/orocos/ros/name_service.rb, line 223 def find_topic_by_name(topic_name) retry_after_update_if_nil do node_name, direction = access_ros_graph do ros_graph.node_graph.find do |node_name, (inputs, outputs)| if inputs.include?(topic_name) break([node_name, :input_port]) elsif outputs.include?(topic_name) break([node_name, :output_port]) end end end if node_name return get(node_name).send(direction, topic_name) end nil end end
# File lib/orocos/ros/name_service.rb, line 172 def get(name, options = Hash.new) options = Kernel.validate_options options, :retry => true, :process => nil _, name = split_name(name) name = "/#{name}".gsub(/\/\//,'/') has_node = access_ros_graph do ros_graph.has_node?(name) end if !has_node if options[:retry] # Wait for a single update of the graph and try # again wait_for_update get(name, :retry => false) else raise Orocos::NotFound, "no such ROS node #{name}" end end slave_uri = begin @ros_master_sync.synchronize do @ros_master.lookup_node(name) end rescue ArgumentError raise Orocos::NotFound, "no such ROS node #{name}" end server = ROSSlave.new(slave_uri, caller_id) return Node.new(self, server, name) end
Provide thread-safe access to the ROS graph API
# File lib/orocos/ros/name_service.rb, line 301 def method_missing(m, *args, &block) access_ros_graph do if ros_graph.respond_to?(m) return ros_graph.send(m, *args, &block) end super end end
# File lib/orocos/ros/name_service.rb, line 203 def names wait_for_update do ros_graph.nodes.dup end end
# File lib/orocos/ros/name_service.rb, line 140 def poll_system_state thread_pool.process_with_options( Hash[:sync_key => @ros_master, :callback => method(:done_system_state)]) do @ros_master_sync.synchronize do state = @ros_master.system_state topics = @ros_master.topics new_update_time = Time.now [new_update_time, NodeGraph.from_system_state(state, topics)] end end end
Processes the latest ROS master exception caught
It raises the exception and reinitializes the @ros_master_exception attribute so that the next error can be caught as well
It must be called with @mutex locked
# File lib/orocos/ros/name_service.rb, line 250 def process_ros_master_exception exception, @ros_master_exception = @ros_master_exception, nil if exception raise exception end end
# File lib/orocos/ros/name_service.rb, line 209 def retry_after_update_if_nil result = yield if !result wait_for_update yield else result end end
# File lib/orocos/ros/name_service.rb, line 136 def to_async(options = Hash.new) Async::ROS::NameService.new(uri, caller_id, options) end
# File lib/orocos/ros/name_service.rb, line 154 def update_system_state(update_time, graph, exception) @mutex.synchronize do if !exception @update_time = update_time @ros_graph = graph end @ros_master_exception ||= exception @updated_graph_signal.broadcast end end
Validates that this name service can be used
@raise any error that has occured during ROS graph update
# File lib/orocos/ros/name_service.rb, line 296 def validate wait_for_update end
Wait for the ROS graph to be updated at least once
@param [Time,nil] if given, the new graph should be newer than
this time. Otherwise, we simply wait for any update
@yield in a context where it is safe to access the ROS graph
object. The block is optional
@return the value returned by the given block, if a block was
given
@raise any error that has occured during ROS graph update
# File lib/orocos/ros/name_service.rb, line 266 def wait_for_update(barrier = Time.now) result = nil @mutex.synchronize do while update_time <= barrier process_ros_master_exception @updated_graph_signal.wait(@mutex) end if block_given? result = yield end process_ros_master_exception end result end