Class: Orocos::ROS::LauncherProcess

Inherits:
ProcessBase show all
Defined in:
lib/orocos/ros/process_manager.rb

Overview

Management of a roslaunch process and its underlying launch file

Instance Attribute Summary collapse

Attributes inherited from ProcessBase

#default_logger, #logged_ports, #model, #name, #name_mappings, #tasks

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ProcessBase

#default_log_file_name, #default_logger_name, #each_task, #get_mapped_name, #log_all_ports, #map_name, #orogen, #register_task, resolve_prefix, #setup_default_logger, #task_names

Constructor Details

#initialize(ros_process_server, name, model) ⇒ LauncherProcess

Returns a new instance of LauncherProcess



140
141
142
143
144
145
146
# File 'lib/orocos/ros/process_manager.rb', line 140

def initialize(ros_process_server, name, model)
    @ros_process_server = ros_process_server
    @nodes = Hash.new
    @launcher = model
    @pid = nil
    super(name, model)
end

Instance Attribute Details

#launcherObject (readonly)

Returns the value of attribute launcher



131
132
133
# File 'lib/orocos/ros/process_manager.rb', line 131

def launcher
  @launcher
end

#pidObject (readonly)

The process ID of this process on the machine of the process server



134
135
136
# File 'lib/orocos/ros/process_manager.rb', line 134

def pid
  @pid
end

#ros_process_serverObject (readonly)

Returns the value of attribute ros_process_server



128
129
130
# File 'lib/orocos/ros/process_manager.rb', line 128

def ros_process_server
  @ros_process_server
end

Class Method Details

.parse_run_options(*names) ⇒ String, Hash

Parse run options to

Returns:

  • (String, Hash)

    Names and options



123
124
125
126
# File 'lib/orocos/ros/process_manager.rb', line 123

def self.parse_run_options(*names)
    options = names.last.kind_of?(Hash) ? names.pop : Hash.new
    [ names, options ]
end

Instance Method Details

#aliveObject



138
# File 'lib/orocos/ros/process_manager.rb', line 138

def alive; !!@pid end

#alive?Boolean

True if the process is running. This is an alias for running?

Returns:

  • (Boolean)


180
# File 'lib/orocos/ros/process_manager.rb', line 180

def alive?; !!@pid end

#dead!(exit_status) ⇒ Object

Called to announce that this process has quit



276
277
278
279
# File 'lib/orocos/ros/process_manager.rb', line 276

def dead!(exit_status)
    LauncherProcess.debug "Announcing launcher '#{@launcher.name}', pid #{@pid} dead!"
    @pid = nil
end

#host_idObject



136
# File 'lib/orocos/ros/process_manager.rb', line 136

def host_id; 'localhost' end

#kill(wait = true) ⇒ Object

Kill the launcher



266
267
268
269
270
271
272
273
# File 'lib/orocos/ros/process_manager.rb', line 266

def kill(wait = true)
    LauncherProcess.debug "Sending SIGTERM to launcher '#{@launcher.name}', pid #{@pid}. Nodes #{@launcher.nodes.map(&:name).join(", ")} will be teared down."
    ::Process.kill('SIGTERM', @pid)
    ros_process_server.kill(self)
    if wait
        status = @launcher.wait_termination
    end
end

#on_localhost?Boolean

Returns:

  • (Boolean)


137
# File 'lib/orocos/ros/process_manager.rb', line 137

def on_localhost?; true end

#running?Boolean

True if the process is running. This is an alias for alive?

Returns:

  • (Boolean)


182
# File 'lib/orocos/ros/process_manager.rb', line 182

def running?; alive? end

#spawn(options = Hash.new) ⇒ int

Spawn the launch file

Returns:

  • (int)

    pid of the launch process



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/orocos/ros/process_manager.rb', line 150

def spawn(options = Hash.new)
    options, unknown_options = Kernel.filter_options options,
        :wait => false,
        :redirect => "ros-#{@launcher.name}.txt"

    wait = options[:wait]
    options.delete(:wait)
    options.merge!(unknown_options)

    task_names.each do |name|
        if ros_process_server.name_service.task_reachable?(name)
            raise ArgumentError, "there is already a task called '#{name}', are you starting the same component twice ?"
        end
    end

    LauncherProcess.debug "Launcher '#{@launcher.name}' spawning"
    @pid = Orocos::ROS.roslaunch(@launcher.project.name, @launcher.name, options)
    LauncherProcess.info "Launcher '#{@launcher.name}' started, pid '#{@pid}'. Nodes #{@launcher.nodes.map(&:name).join(", ")}  available."

    @pid
end

#task(name) ⇒ Orocos::ROS::Node

Retrieve the task (node) using the internal name service instance

Returns:

Raises:



175
176
177
# File 'lib/orocos/ros/process_manager.rb', line 175

def task(name)
    super(name, ros_process_server.name_service)
end

#wait_running(timeout = nil) ⇒ Boolean

Wait for all nodes of the launcher to become available

Returns:

  • (Boolean)

    True if process is running, false otherwise

Raises:



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/orocos/ros/process_manager.rb', line 187

def wait_running(timeout = nil)

    is_running = Orocos::Process.wait_running(self,timeout) do |launcher_process|
        all_nodes_available = true
        all_topics_available = true
        topics = []
        begin
            nodes = launcher_process.launcher.nodes
            if nodes.empty?
                LauncherProcess.warn "launcher_process: #{launcher_process} does not have any nodes"
            end

            nodes.each do |n|
                # Wait till node is visible in ROS
                if !ROS.rosnode_running?(n.name)
                    all_nodes_available = false
                    break
                end

                # Check if the node can be seen in the nameservice as
                # well
                task = ros_process_server.name_service.get(n.name)

                # Try to check whether the topics in the spec are already available
                # Note that we have to try to instanciate write and reader and using
                # to_orocos_port in order to make sure the ROS node is really accessible
                if spec = ROS.node_spec_by_node_name(n.name)
                    spec.each_input_port do |port|
                        if task.port(port.topic_name)
                            topics << port.topic_name
                            next
                        end

                        all_topics_available = false
                        break
                    end

                    spec.each_output_port do |port|
                        if task.port(port.topic_name)
                            topics << port.topic_name
                            next
                        end
                        all_topics_available = false
                        break
                    end
                else
                    raise ArgumentError, "No ROS Node specification available for #{n.name}"
                end
            end
        rescue Orocos::NotFound => e
            all_nodes_available = false
            all_topics_available = false
        end

        if ! (all_nodes_available && all_topics_available)
            LauncherProcess.debug "reachable nodes: #{nodes.map(&:name).join(", ")}"
            LauncherProcess.debug "reachable topics: #{topics.join(", ")}"
        end

        all_nodes_available && all_topics_available
    end

    is_running
end

#wait_termination(timeout = nil) ⇒ Process::Status

Wait for termination of the launcher process

Returns:

  • (Process::Status)

    Final process status



254
255
256
257
258
259
260
261
262
263
# File 'lib/orocos/ros/process_manager.rb', line 254

def wait_termination(timeout = nil)
    if timeout
        raise NotImplementedError, "ROS::ProcessManager#wait_termination cannot be called with a timeout"
    end

    _, status = begin ::Process.waitpid2(@pid, ::Process::WUNTRACED | Process::WNOHANG)
                  rescue Errno::ECHILD
                  end
    status
end