roby 0.7.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +7 -5
- data/Manifest.txt +91 -16
- data/README.txt +24 -24
- data/Rakefile +92 -64
- data/app/config/app.yml +42 -43
- data/app/config/init.rb +26 -0
- data/benchmark/alloc_misc.rb +123 -0
- data/benchmark/discovery_latency.rb +67 -0
- data/benchmark/garbage_collection.rb +48 -0
- data/benchmark/genom.rb +31 -0
- data/benchmark/transactions.rb +62 -0
- data/bin/roby +1 -1
- data/bin/roby-log +16 -6
- data/doc/guide/.gitignore +2 -0
- data/doc/guide/config.yaml +34 -0
- data/doc/guide/ext/init.rb +14 -0
- data/doc/guide/ext/previous_next.rb +40 -0
- data/doc/guide/ext/rdoc_links.rb +33 -0
- data/doc/guide/index.rdoc +16 -0
- data/doc/guide/overview.rdoc +62 -0
- data/doc/guide/plan_modifications.rdoc +67 -0
- data/doc/guide/src/abstraction/achieve_with.page +8 -0
- data/doc/guide/src/abstraction/forwarding.page +8 -0
- data/doc/guide/src/abstraction/hierarchy.page +19 -0
- data/doc/guide/src/abstraction/index.page +28 -0
- data/doc/guide/src/abstraction/task_models.page +13 -0
- data/doc/guide/src/basics.template +6 -0
- data/doc/guide/src/basics/app.page +139 -0
- data/doc/guide/src/basics/code_examples.page +33 -0
- data/doc/guide/src/basics/dry.page +69 -0
- data/doc/guide/src/basics/errors.page +443 -0
- data/doc/guide/src/basics/events.page +179 -0
- data/doc/guide/src/basics/hierarchy.page +275 -0
- data/doc/guide/src/basics/index.page +11 -0
- data/doc/guide/src/basics/log_replay/goForward_1.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_2.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_3.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_4.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_5.png +0 -0
- data/doc/guide/src/basics/log_replay/hierarchy_error_1.png +0 -0
- data/doc/guide/src/basics/log_replay/hierarchy_error_2.png +0 -0
- data/doc/guide/src/basics/log_replay/hierarchy_error_3.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_1.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_2.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_3.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_4.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_log_main_window.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_log_relation_window.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_replay_event_representation.png +0 -0
- data/doc/guide/src/basics/plan_objects.page +71 -0
- data/doc/guide/src/basics/relations_display.page +203 -0
- data/doc/guide/src/basics/roby_cycle_overview.png +0 -0
- data/doc/guide/src/basics/shell.page +102 -0
- data/doc/guide/src/basics/summary.page +32 -0
- data/doc/guide/src/basics/tasks.page +357 -0
- data/doc/guide/src/basics_shell_header.txt +16 -0
- data/doc/guide/src/cycle/cycle-overview.png +0 -0
- data/doc/guide/src/cycle/cycle-overview.svg +208 -0
- data/doc/guide/src/cycle/error_handling.page +168 -0
- data/doc/guide/src/cycle/error_instantaneous_repair.png +0 -0
- data/doc/guide/src/cycle/error_instantaneous_repair.svg +1224 -0
- data/doc/guide/src/cycle/garbage_collection.page +10 -0
- data/doc/guide/src/cycle/index.page +23 -0
- data/doc/guide/src/cycle/propagation.page +154 -0
- data/doc/guide/src/cycle/propagation_diamond.png +0 -0
- data/doc/guide/src/cycle/propagation_diamond.svg +1279 -0
- data/doc/guide/src/default.css +319 -0
- data/doc/guide/src/default.template +74 -0
- data/doc/guide/src/htmldoc.metainfo +20 -0
- data/doc/guide/src/htmldoc.virtual +18 -0
- data/doc/guide/src/images/bodybg.png +0 -0
- data/doc/guide/src/images/contbg.png +0 -0
- data/doc/guide/src/images/footerbg.png +0 -0
- data/doc/guide/src/images/gradient1.png +0 -0
- data/doc/guide/src/images/gradient2.png +0 -0
- data/doc/guide/src/index.page +7 -0
- data/doc/guide/src/introduction/index.page +29 -0
- data/doc/guide/src/introduction/install.page +133 -0
- data/doc/{papers.rdoc → guide/src/introduction/publications.page} +5 -2
- data/doc/{videos.rdoc → guide/src/introduction/videos.page} +4 -2
- data/doc/guide/src/plugins/fault_tolerance.page +44 -0
- data/doc/guide/src/plugins/index.page +11 -0
- data/doc/guide/src/plugins/subsystems.page +45 -0
- data/doc/guide/src/relations/dependency.page +89 -0
- data/doc/guide/src/relations/index.page +12 -0
- data/doc/misc/update_github +24 -0
- data/doc/tutorials/02-GoForward.rdoc +3 -3
- data/ext/graph/graph.cc +46 -0
- data/lib/roby.rb +57 -22
- data/lib/roby/app.rb +132 -112
- data/lib/roby/app/plugins/rake.rb +21 -0
- data/lib/roby/app/rake.rb +0 -7
- data/lib/roby/app/run.rb +1 -1
- data/lib/roby/app/scripts/distributed.rb +1 -2
- data/lib/roby/app/scripts/generate/bookmarks.rb +1 -1
- data/lib/roby/app/scripts/results.rb +2 -1
- data/lib/roby/app/scripts/run.rb +6 -2
- data/lib/roby/app/scripts/shell.rb +11 -11
- data/lib/roby/config.rb +1 -1
- data/lib/roby/decision_control.rb +62 -3
- data/lib/roby/distributed.rb +4 -0
- data/lib/roby/distributed/base.rb +8 -0
- data/lib/roby/distributed/communication.rb +12 -8
- data/lib/roby/distributed/connection_space.rb +61 -44
- data/lib/roby/distributed/distributed_object.rb +1 -1
- data/lib/roby/distributed/notifications.rb +22 -30
- data/lib/roby/distributed/peer.rb +13 -8
- data/lib/roby/distributed/proxy.rb +5 -5
- data/lib/roby/distributed/subscription.rb +4 -4
- data/lib/roby/distributed/transaction.rb +3 -3
- data/lib/roby/event.rb +176 -110
- data/lib/roby/exceptions.rb +12 -4
- data/lib/roby/execution_engine.rb +1604 -0
- data/lib/roby/external_process_task.rb +225 -0
- data/lib/roby/graph.rb +0 -6
- data/lib/roby/interface.rb +221 -137
- data/lib/roby/log/console.rb +5 -3
- data/lib/roby/log/data_stream.rb +94 -16
- data/lib/roby/log/dot.rb +8 -8
- data/lib/roby/log/event_stream.rb +13 -3
- data/lib/roby/log/file.rb +43 -18
- data/lib/roby/log/gui/basic_display_ui.rb +89 -0
- data/lib/roby/log/gui/chronicle_view_ui.rb +90 -0
- data/lib/roby/log/gui/data_displays.rb +4 -5
- data/lib/roby/log/gui/data_displays_ui.rb +146 -0
- data/lib/roby/log/gui/relations.rb +18 -18
- data/lib/roby/log/gui/relations_ui.rb +120 -0
- data/lib/roby/log/gui/relations_view_ui.rb +144 -0
- data/lib/roby/log/gui/replay.rb +41 -13
- data/lib/roby/log/gui/replay_controls.rb +3 -0
- data/lib/roby/log/gui/replay_controls.ui +133 -110
- data/lib/roby/log/gui/replay_controls_ui.rb +249 -0
- data/lib/roby/log/hooks.rb +19 -18
- data/lib/roby/log/logger.rb +7 -6
- data/lib/roby/log/notifications.rb +4 -4
- data/lib/roby/log/plan_rebuilder.rb +20 -22
- data/lib/roby/log/relations.rb +44 -16
- data/lib/roby/log/server.rb +1 -4
- data/lib/roby/log/timings.rb +88 -19
- data/lib/roby/plan-object.rb +135 -11
- data/lib/roby/plan.rb +408 -224
- data/lib/roby/planning/loops.rb +32 -25
- data/lib/roby/planning/model.rb +157 -51
- data/lib/roby/planning/task.rb +47 -20
- data/lib/roby/query.rb +128 -92
- data/lib/roby/relations.rb +254 -136
- data/lib/roby/relations/conflicts.rb +6 -9
- data/lib/roby/relations/dependency.rb +358 -0
- data/lib/roby/relations/ensured.rb +0 -1
- data/lib/roby/relations/error_handling.rb +0 -1
- data/lib/roby/relations/events.rb +0 -2
- data/lib/roby/relations/executed_by.rb +26 -11
- data/lib/roby/relations/planned_by.rb +14 -14
- data/lib/roby/robot.rb +46 -0
- data/lib/roby/schedulers/basic.rb +34 -0
- data/lib/roby/standalone.rb +4 -0
- data/lib/roby/standard_errors.rb +21 -15
- data/lib/roby/state/events.rb +5 -4
- data/lib/roby/support.rb +107 -6
- data/lib/roby/task-operations.rb +23 -19
- data/lib/roby/task.rb +522 -148
- data/lib/roby/task_index.rb +80 -0
- data/lib/roby/test/common.rb +283 -44
- data/lib/roby/test/distributed.rb +53 -37
- data/lib/roby/test/testcase.rb +9 -204
- data/lib/roby/test/tools.rb +3 -3
- data/lib/roby/transactions.rb +154 -111
- data/lib/roby/transactions/proxy.rb +40 -7
- data/manifest.xml +20 -0
- data/plugins/fault_injection/README.txt +0 -3
- data/plugins/fault_injection/Rakefile +2 -8
- data/plugins/fault_injection/app.rb +1 -1
- data/plugins/fault_injection/fault_injection.rb +3 -3
- data/plugins/fault_injection/test/test_fault_injection.rb +19 -25
- data/plugins/subsystems/README.txt +0 -3
- data/plugins/subsystems/Rakefile +2 -7
- data/plugins/subsystems/app.rb +27 -16
- data/plugins/subsystems/test/app/config/init.rb +3 -0
- data/plugins/subsystems/test/app/planners/main.rb +1 -1
- data/plugins/subsystems/test/app/tasks/services.rb +1 -1
- data/plugins/subsystems/test/test_subsystems.rb +23 -16
- data/test/distributed/test_communication.rb +32 -15
- data/test/distributed/test_connection.rb +28 -26
- data/test/distributed/test_execution.rb +59 -54
- data/test/distributed/test_mixed_plan.rb +34 -34
- data/test/distributed/test_plan_notifications.rb +26 -26
- data/test/distributed/test_protocol.rb +57 -48
- data/test/distributed/test_query.rb +11 -7
- data/test/distributed/test_remote_plan.rb +71 -71
- data/test/distributed/test_transaction.rb +50 -47
- data/test/mockups/external_process +28 -0
- data/test/planning/test_loops.rb +163 -119
- data/test/planning/test_model.rb +3 -3
- data/test/planning/test_task.rb +27 -7
- data/test/relations/test_conflicts.rb +3 -3
- data/test/relations/test_dependency.rb +324 -0
- data/test/relations/test_ensured.rb +2 -2
- data/test/relations/test_executed_by.rb +94 -19
- data/test/relations/test_planned_by.rb +11 -9
- data/test/suite_core.rb +6 -3
- data/test/suite_distributed.rb +1 -0
- data/test/suite_planning.rb +1 -0
- data/test/suite_relations.rb +2 -2
- data/test/tasks/test_external_process.rb +126 -0
- data/test/{test_thread_task.rb → tasks/test_thread_task.rb} +17 -20
- data/test/test_bgl.rb +21 -1
- data/test/test_event.rb +229 -155
- data/test/test_exceptions.rb +79 -80
- data/test/test_execution_engine.rb +987 -0
- data/test/test_gui.rb +1 -1
- data/test/test_interface.rb +11 -5
- data/test/test_log.rb +18 -7
- data/test/test_log_server.rb +1 -0
- data/test/test_plan.rb +229 -395
- data/test/test_query.rb +193 -35
- data/test/test_relations.rb +88 -8
- data/test/test_state.rb +55 -37
- data/test/test_support.rb +1 -1
- data/test/test_task.rb +371 -218
- data/test/test_testcase.rb +32 -16
- data/test/test_transactions.rb +211 -170
- data/test/test_transactions_proxy.rb +37 -19
- metadata +169 -71
- data/.gitignore +0 -29
- data/doc/styles/allison.css +0 -314
- data/doc/styles/allison.js +0 -316
- data/doc/styles/allison.rb +0 -276
- data/doc/styles/jamis.rb +0 -593
- data/lib/roby/control.rb +0 -746
- data/lib/roby/executives/simple.rb +0 -30
- data/lib/roby/propagation.rb +0 -562
- data/lib/roby/relations/hierarchy.rb +0 -239
- data/lib/roby/transactions/updates.rb +0 -139
- data/test/relations/test_hierarchy.rb +0 -158
- data/test/test_control.rb +0 -399
- data/test/test_propagation.rb +0 -210
data/lib/roby/planning/loops.rb
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'roby/planning/task'
|
|
2
|
-
|
|
3
1
|
module Roby
|
|
4
2
|
# This class unrolls a loop in the plan. It maintains +lookahead+ patterns
|
|
5
3
|
# developped at all times by calling an external planner, and manages them.
|
|
@@ -68,29 +66,40 @@ module Roby
|
|
|
68
66
|
|
|
69
67
|
# The planner model we should use
|
|
70
68
|
argument :planner_model
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
|
|
70
|
+
# The planner method name. This is not a mandatory argument as
|
|
71
|
+
# otherwise we would break logging and distributed Roby: this attribute
|
|
72
|
+
# can hold a MethodDefinition object that cannot be shared.
|
|
73
|
+
#
|
|
74
|
+
# Anyway, the only meaningful argument in distributed context is the
|
|
75
|
+
# method name itself. Event method_options could be removed in the
|
|
76
|
+
# future.
|
|
77
|
+
def planning_method
|
|
78
|
+
arguments[:planning_method]
|
|
79
|
+
end
|
|
73
80
|
# The planner method options
|
|
74
81
|
argument :method_options
|
|
75
82
|
|
|
83
|
+
# The method name. This can be nil a FreeMethod is used for planning
|
|
84
|
+
argument :method_name
|
|
85
|
+
|
|
76
86
|
# Filters the options in +options+, splitting between the options that
|
|
77
87
|
# are specific to the planning task and those that are to be forwarded
|
|
78
88
|
# to the planner itself
|
|
79
|
-
def self.filter_options(options)
|
|
89
|
+
def self.filter_options(options)
|
|
80
90
|
task_arguments, planning_options = Kernel.filter_options options,
|
|
81
91
|
:period => nil,
|
|
82
92
|
:lookahead => 1,
|
|
83
93
|
:planner_model => nil,
|
|
94
|
+
:planning_method => nil,
|
|
84
95
|
:planned_model => Roby::Task,
|
|
85
96
|
:method_name => nil,
|
|
86
97
|
:method_options => {},
|
|
87
98
|
:planning_owners => nil
|
|
88
99
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
raise ArgumentError, "required argument :planner_model missing"
|
|
93
|
-
elsif task_arguments[:lookahead] < 0
|
|
100
|
+
task_arguments = PlanningTask.validate_planning_options(task_arguments)
|
|
101
|
+
|
|
102
|
+
if task_arguments[:lookahead] < 0
|
|
94
103
|
raise ArgumentError, "lookahead must be positive"
|
|
95
104
|
end
|
|
96
105
|
task_arguments[:period] ||= nil
|
|
@@ -109,7 +118,7 @@ module Roby
|
|
|
109
118
|
if period && period > 0
|
|
110
119
|
@periodic_trigger = State.on_delta :t => period
|
|
111
120
|
periodic_trigger.disable
|
|
112
|
-
periodic_trigger.
|
|
121
|
+
periodic_trigger.signals event(:loop_start)
|
|
113
122
|
end
|
|
114
123
|
|
|
115
124
|
@patterns = []
|
|
@@ -135,17 +144,17 @@ module Roby
|
|
|
135
144
|
# +context+ is forwarded to the planned task
|
|
136
145
|
def append_pattern(*context)
|
|
137
146
|
# Create the new pattern
|
|
138
|
-
task_arguments = arguments.slice(:planner_model, :planned_model, :
|
|
147
|
+
task_arguments = arguments.slice(:planner_model, :planned_model, :planning_method)
|
|
139
148
|
task_arguments[:method_options] = method_options.dup
|
|
140
149
|
task_arguments[:method_options][:pattern_id] = @pattern_id
|
|
141
150
|
@pattern_id += 1
|
|
142
151
|
|
|
143
152
|
planning = PlanningTask.new(task_arguments)
|
|
144
153
|
planned = planning.planned_task
|
|
145
|
-
planned.
|
|
146
|
-
planned.
|
|
147
|
-
planned.
|
|
148
|
-
main_task.
|
|
154
|
+
planned.forward_to(:start, self, :loop_start)
|
|
155
|
+
planned.forward_to(:success, self, :loop_success)
|
|
156
|
+
planned.forward_to(:stop, self, :loop_end)
|
|
157
|
+
main_task.depends_on planned, :model => planned.model
|
|
149
158
|
|
|
150
159
|
# Schedule it. We start the new pattern when these three conditions are met:
|
|
151
160
|
# * it has been planned (planning has finished)
|
|
@@ -175,13 +184,15 @@ module Roby
|
|
|
175
184
|
if last_planning.finished?
|
|
176
185
|
planning.start!(*context)
|
|
177
186
|
else
|
|
178
|
-
last_planning.event(:success).
|
|
187
|
+
last_planning.event(:success).
|
|
188
|
+
filter(*context).
|
|
189
|
+
signals(planning.event(:start))
|
|
179
190
|
end
|
|
180
191
|
end
|
|
181
192
|
command &= precondition
|
|
182
193
|
|
|
183
194
|
patterns.unshift([planning, user_command])
|
|
184
|
-
command.
|
|
195
|
+
command.signals(planned.event(:start))
|
|
185
196
|
planning
|
|
186
197
|
end
|
|
187
198
|
|
|
@@ -189,13 +200,9 @@ module Roby
|
|
|
189
200
|
# as lookahead requires. Kills the currently running pattern (if there
|
|
190
201
|
# is one).
|
|
191
202
|
event :reinit do |context|
|
|
192
|
-
unless running?
|
|
193
|
-
raise ArgumentError, "#reinit called, but the loop is not running"
|
|
194
|
-
end
|
|
195
|
-
|
|
196
203
|
did_reinit = []
|
|
197
204
|
|
|
198
|
-
# Remove all
|
|
205
|
+
# Remove all depends_on relations and all pending patterns from
|
|
199
206
|
# the pattern set.
|
|
200
207
|
for pattern in patterns
|
|
201
208
|
old_planning, ev = pattern
|
|
@@ -216,7 +223,7 @@ module Roby
|
|
|
216
223
|
did_reinit.
|
|
217
224
|
map { |ev| ev.when_unreachable }.
|
|
218
225
|
inject { |a, b| a & b }.
|
|
219
|
-
|
|
226
|
+
forward_to event(:reinit)
|
|
220
227
|
end
|
|
221
228
|
end
|
|
222
229
|
on :reinit do |ev|
|
|
@@ -242,7 +249,7 @@ module Roby
|
|
|
242
249
|
new_planning = append_pattern
|
|
243
250
|
first_planning ||= new_planning
|
|
244
251
|
end
|
|
245
|
-
|
|
252
|
+
signals(:start, first_planning, :start)
|
|
246
253
|
end
|
|
247
254
|
|
|
248
255
|
emit :start
|
data/lib/roby/planning/model.rb
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
require 'roby/planning/task'
|
|
2
|
-
require 'roby/task'
|
|
3
|
-
require 'roby/control'
|
|
4
|
-
require 'roby/plan'
|
|
5
|
-
require 'utilrb/module/ancestor_p'
|
|
6
|
-
require 'set'
|
|
7
|
-
|
|
8
1
|
module Roby
|
|
9
2
|
# The Planning module provides basic tools to create plans (graph of tasks
|
|
10
3
|
# and events)
|
|
@@ -19,6 +12,33 @@ module Roby
|
|
|
19
12
|
end
|
|
20
13
|
end
|
|
21
14
|
|
|
15
|
+
MethodArgDescription = Struct.new :name, :doc, :required
|
|
16
|
+
class MethodDescription
|
|
17
|
+
attr_reader :doc
|
|
18
|
+
|
|
19
|
+
attr_reader :arguments
|
|
20
|
+
|
|
21
|
+
attr_predicate :advanced?
|
|
22
|
+
|
|
23
|
+
def initialize(doc = nil)
|
|
24
|
+
@doc = doc
|
|
25
|
+
@arguments = []
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def required_arg(name, doc)
|
|
29
|
+
arguments << MethodArgDescription.new(name, doc, true)
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
def optional_arg(name, doc)
|
|
33
|
+
arguments << MethodArgDescription.new(name, doc, false)
|
|
34
|
+
self
|
|
35
|
+
end
|
|
36
|
+
def advanced
|
|
37
|
+
@advanced = true
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
22
42
|
# Raised a method has found no valid development
|
|
23
43
|
class NotFound < PlanModelError
|
|
24
44
|
# The name of the method which has failed
|
|
@@ -35,33 +55,43 @@ module Roby
|
|
|
35
55
|
super(planner)
|
|
36
56
|
end
|
|
37
57
|
|
|
38
|
-
|
|
58
|
+
def pretty_print(pp)
|
|
39
59
|
if errors.empty?
|
|
40
|
-
"no candidate for #{method_name}(#{method_options})"
|
|
60
|
+
pp.text "no candidate for #{method_name}(#{method_options})"
|
|
41
61
|
else
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
first, *rem = Roby.filter_backtrace(backtrace)
|
|
63
|
+
pp.text "cannot develop a #{method_name}(#{method_options.to_s[1..-2]}) method"
|
|
64
|
+
pp.breakable
|
|
65
|
+
pp.group(4, " ") do
|
|
66
|
+
rem.each do |line|
|
|
67
|
+
pp.text "from #{line}"
|
|
68
|
+
pp.breakable
|
|
69
|
+
end
|
|
70
|
+
end
|
|
44
71
|
|
|
45
|
-
|
|
72
|
+
pp.breakable
|
|
46
73
|
errors.each do |m, error|
|
|
47
|
-
|
|
48
|
-
|
|
74
|
+
if error.kind_of?(NotFound)
|
|
75
|
+
first, *rem = *Roby.filter_backtrace(error.backtrace)
|
|
76
|
+
pp.text "in method #{m}"
|
|
77
|
+
pp.breakable
|
|
78
|
+
error.pretty_print(pp)
|
|
79
|
+
else
|
|
80
|
+
first, *rem = *Roby.filter_backtrace(error.backtrace)
|
|
81
|
+
pp.text "planning method #{m} failed"
|
|
82
|
+
pp.breakable
|
|
83
|
+
pp.text "#{first}: #{error.message}"
|
|
84
|
+
pp.breakable
|
|
85
|
+
pp.group(4, " ") do
|
|
86
|
+
rem.each do |line|
|
|
87
|
+
pp.text "from #{line}"
|
|
88
|
+
pp.breakable
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
49
92
|
end
|
|
50
|
-
full
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def full_message
|
|
55
|
-
msg = message
|
|
56
|
-
first, *rem = *Roby.filter_backtrace(backtrace)
|
|
57
|
-
|
|
58
|
-
full = "#{first}: #{msg}\n from #{rem.join("\n from ")}"
|
|
59
|
-
errors.each do |m, error|
|
|
60
|
-
first = error.backtrace.first
|
|
61
|
-
full << "\n#{first} #{m} failed because of #{error.full_message}"
|
|
62
93
|
end
|
|
63
|
-
|
|
64
|
-
end
|
|
94
|
+
end
|
|
65
95
|
end
|
|
66
96
|
|
|
67
97
|
# Some common tools for Planner and Library
|
|
@@ -130,7 +160,15 @@ module Roby
|
|
|
130
160
|
# Call the method definition
|
|
131
161
|
def call(planner); body.call(planner) end
|
|
132
162
|
|
|
133
|
-
def to_s
|
|
163
|
+
def to_s
|
|
164
|
+
opts = options.dup
|
|
165
|
+
opts.delete :id
|
|
166
|
+
"#{name}:#{id}(#{opts.to_s[1..-2]})"
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
class FreeMethod < MethodDefinition
|
|
171
|
+
def call(planner); planner.instance_eval(&body) end
|
|
134
172
|
end
|
|
135
173
|
|
|
136
174
|
# The model of a planning method. This does not define an actual
|
|
@@ -151,7 +189,9 @@ module Roby
|
|
|
151
189
|
# The model options, as a Hash
|
|
152
190
|
attr_reader :options
|
|
153
191
|
|
|
154
|
-
def initialize(name, options = Hash.new)
|
|
192
|
+
def initialize(name, options = Hash.new)
|
|
193
|
+
@name, @options = name, options
|
|
194
|
+
end
|
|
155
195
|
def ==(model)
|
|
156
196
|
name == model.name && options == model.options
|
|
157
197
|
end
|
|
@@ -210,6 +250,8 @@ module Roby
|
|
|
210
250
|
def to_s; "#{name}(#{options})" end
|
|
211
251
|
end
|
|
212
252
|
|
|
253
|
+
PlanningMethod = Struct.new :name, :model, :description, :instances
|
|
254
|
+
|
|
213
255
|
# A planner searches a suitable development for a set of methods.
|
|
214
256
|
# Methods are defined using Planner::method. You can then ask
|
|
215
257
|
# for a plan by sending your method name to the Planner object
|
|
@@ -321,6 +363,25 @@ module Roby
|
|
|
321
363
|
end
|
|
322
364
|
end
|
|
323
365
|
|
|
366
|
+
# call-seq:
|
|
367
|
+
# describe(first_line, second_line, ...).
|
|
368
|
+
# required_arg(arg_name, arg_doc).
|
|
369
|
+
# optional_arg(arg_name, arg_doc)
|
|
370
|
+
#
|
|
371
|
+
# Describes the next method or method model. It adds a description
|
|
372
|
+
# text for the method, which can be shown for instance by the
|
|
373
|
+
# shell's "action" command. It is also possible to describe the
|
|
374
|
+
# expected method arguments.
|
|
375
|
+
def self.describe(*text)
|
|
376
|
+
if text.empty?
|
|
377
|
+
text = ["(no description set)"]
|
|
378
|
+
else
|
|
379
|
+
text.map! { |s| s.to_str }
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
@next_method_description = MethodDescription.new(text)
|
|
383
|
+
end
|
|
384
|
+
|
|
324
385
|
# call-seq:
|
|
325
386
|
# method(name, option1 => value1, option2 => value2) { } => method definition
|
|
326
387
|
# method(name, option1 => value1, option2 => value2) => method model
|
|
@@ -410,7 +471,7 @@ module Roby
|
|
|
410
471
|
def self.method(name, options = Hash.new, &body)
|
|
411
472
|
name, options = validate_method_query(name, options)
|
|
412
473
|
|
|
413
|
-
# Define the method enumerator and the method
|
|
474
|
+
# Define the method enumerator and the method public interface
|
|
414
475
|
if !respond_to?("#{name}_methods")
|
|
415
476
|
inherited_enumerable("#{name}_method", "#{name}_methods", :map => true) { Hash.new }
|
|
416
477
|
class_eval <<-PLANNING_METHOD_END
|
|
@@ -421,7 +482,17 @@ module Roby
|
|
|
421
482
|
cached_enum("#{name}_method", "#{name}_methods", true)
|
|
422
483
|
end
|
|
423
484
|
PLANNING_METHOD_END
|
|
485
|
+
singleton_class.class_eval do
|
|
486
|
+
attr_reader "#{name}_description"
|
|
487
|
+
end
|
|
424
488
|
end
|
|
489
|
+
if @next_method_description
|
|
490
|
+
if instance_variable_get("@#{name}_description")
|
|
491
|
+
raise "#{name} already has a description"
|
|
492
|
+
end
|
|
493
|
+
instance_variable_set("@#{name}_description", @next_method_description)
|
|
494
|
+
@next_method_description = nil
|
|
495
|
+
end
|
|
425
496
|
|
|
426
497
|
# We are updating the method model
|
|
427
498
|
if !body
|
|
@@ -463,7 +534,8 @@ module Roby
|
|
|
463
534
|
end
|
|
464
535
|
temp_method_name = "m#{@@temp_method_id += 1}"
|
|
465
536
|
define_method(temp_method_name, &body)
|
|
466
|
-
|
|
537
|
+
mdef = MethodDefinition.new(name, options, instance_method(temp_method_name))
|
|
538
|
+
send("#{name}_methods")[method_id] = mdef
|
|
467
539
|
end
|
|
468
540
|
@@temp_method_id = 0
|
|
469
541
|
|
|
@@ -479,6 +551,33 @@ module Roby
|
|
|
479
551
|
names
|
|
480
552
|
end
|
|
481
553
|
|
|
554
|
+
def self.planning_methods
|
|
555
|
+
names = methods.map do |method_name|
|
|
556
|
+
if method_name =~ /^each_(\w+)_method$/
|
|
557
|
+
$1
|
|
558
|
+
end
|
|
559
|
+
end.compact.sort
|
|
560
|
+
|
|
561
|
+
names.map do |name|
|
|
562
|
+
desc = PlanningMethod.new
|
|
563
|
+
desc.name = name
|
|
564
|
+
desc.description = planning_method_description(name)
|
|
565
|
+
#desc.model = method_model(name)
|
|
566
|
+
#desc.instances = Array.new
|
|
567
|
+
#send("each_#{name}_method") do |instance|
|
|
568
|
+
# desc.instances << instance
|
|
569
|
+
#end
|
|
570
|
+
desc
|
|
571
|
+
end
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
def self.planning_method_description(name)
|
|
575
|
+
return instance_variable_get("@#{name}_description") || MethodDescription.new
|
|
576
|
+
end
|
|
577
|
+
def planning_method_description(name)
|
|
578
|
+
self.class.planning_method_description(name)
|
|
579
|
+
end
|
|
580
|
+
|
|
482
581
|
def self.clear_model
|
|
483
582
|
planning_methods_names.each do |name|
|
|
484
583
|
remove_planning_method(name)
|
|
@@ -608,6 +707,13 @@ module Roby
|
|
|
608
707
|
MethodModel.new(name, :returns => Task)
|
|
609
708
|
end
|
|
610
709
|
|
|
710
|
+
# Creates a TaskSequence with the given tasks
|
|
711
|
+
def sequence(*tasks)
|
|
712
|
+
seq = Sequence.new
|
|
713
|
+
tasks.each { |t| seq << t }
|
|
714
|
+
seq
|
|
715
|
+
end
|
|
716
|
+
|
|
611
717
|
# Creates a planning task which will call the same planning method
|
|
612
718
|
# than the one currently being generated.
|
|
613
719
|
#
|
|
@@ -653,9 +759,8 @@ module Roby
|
|
|
653
759
|
elsif planning_options[:args] && !planning_options[:args].empty?
|
|
654
760
|
raise ArgumentError, "provided method-specific options through both :args and the option hash"
|
|
655
761
|
end
|
|
656
|
-
@arguments.push(method_options)
|
|
657
762
|
|
|
658
|
-
Planning.debug { "planning #{name}[#{
|
|
763
|
+
Planning.debug { "planning #{name}[#{method_options}]" }
|
|
659
764
|
|
|
660
765
|
# Check for recursion
|
|
661
766
|
if (options[:id] && @stack.include?([name, options[:id]])) || (!options[:id] && @stack.find { |n, _| n == name })
|
|
@@ -678,7 +783,7 @@ module Roby
|
|
|
678
783
|
all_returns.compact!
|
|
679
784
|
|
|
680
785
|
for return_type in all_returns
|
|
681
|
-
if task = find_reusable_task(return_type)
|
|
786
|
+
if task = find_reusable_task(return_type, method_options)
|
|
682
787
|
return task
|
|
683
788
|
end
|
|
684
789
|
end
|
|
@@ -689,7 +794,7 @@ module Roby
|
|
|
689
794
|
end
|
|
690
795
|
|
|
691
796
|
# Call the methods
|
|
692
|
-
call_planning_methods(Hash.new,
|
|
797
|
+
call_planning_methods(Hash.new, method_options, *methods)
|
|
693
798
|
|
|
694
799
|
rescue Interrupt
|
|
695
800
|
raise
|
|
@@ -697,22 +802,19 @@ module Roby
|
|
|
697
802
|
rescue NotFound => e
|
|
698
803
|
e.method_name = name
|
|
699
804
|
e.method_options = options
|
|
700
|
-
raise e
|
|
701
|
-
|
|
702
|
-
ensure
|
|
703
|
-
@arguments.pop
|
|
805
|
+
raise e.dup, e.message, caller(1)
|
|
704
806
|
end
|
|
705
807
|
|
|
706
|
-
def find_reusable_task(return_type)
|
|
808
|
+
def find_reusable_task(return_type, method_options)
|
|
707
809
|
query = plan.find_tasks.
|
|
708
|
-
which_fullfills(return_type,
|
|
810
|
+
which_fullfills(return_type, method_options).
|
|
709
811
|
self_owned.
|
|
710
812
|
not_abstract.
|
|
711
813
|
not_finished.
|
|
712
814
|
roots(TaskStructure::Hierarchy)
|
|
713
815
|
|
|
714
816
|
for candidate in query
|
|
715
|
-
Planning.debug { "selecting task #{candidate} instead of planning #{return_type}[#{
|
|
817
|
+
Planning.debug { "selecting task #{candidate} instead of planning #{return_type}[#{method_options}]" }
|
|
716
818
|
return candidate
|
|
717
819
|
end
|
|
718
820
|
nil
|
|
@@ -724,9 +826,10 @@ module Roby
|
|
|
724
826
|
# Tries to find a successfull development in the provided method list.
|
|
725
827
|
#
|
|
726
828
|
# It raises NotFound if none of the methods returned successfully
|
|
727
|
-
def call_planning_methods(errors,
|
|
829
|
+
def call_planning_methods(errors, method_options, method, *methods)
|
|
728
830
|
begin
|
|
729
831
|
@stack.push [method.name, method.id]
|
|
832
|
+
@arguments.push(method_options)
|
|
730
833
|
Planning.debug { "calling #{method.name}:#{method.id} with arguments #{arguments}" }
|
|
731
834
|
begin
|
|
732
835
|
result = method.call(self)
|
|
@@ -742,7 +845,7 @@ module Roby
|
|
|
742
845
|
end
|
|
743
846
|
|
|
744
847
|
# Insert resulting tasks in +plan+
|
|
745
|
-
plan.
|
|
848
|
+
plan.add(result)
|
|
746
849
|
|
|
747
850
|
expected_return = method.returns
|
|
748
851
|
if expected_return
|
|
@@ -762,6 +865,7 @@ module Roby
|
|
|
762
865
|
result
|
|
763
866
|
|
|
764
867
|
ensure
|
|
868
|
+
@arguments.pop
|
|
765
869
|
@stack.pop
|
|
766
870
|
end
|
|
767
871
|
|
|
@@ -771,7 +875,7 @@ module Roby
|
|
|
771
875
|
if methods.empty?
|
|
772
876
|
raise NotFound.new(self, errors)
|
|
773
877
|
else
|
|
774
|
-
call_planning_methods(errors,
|
|
878
|
+
call_planning_methods(errors, method_options, *methods)
|
|
775
879
|
end
|
|
776
880
|
end
|
|
777
881
|
|
|
@@ -782,20 +886,22 @@ module Roby
|
|
|
782
886
|
def make_loop(options = {}, &block)
|
|
783
887
|
raise ArgumentError, "no block given" unless block
|
|
784
888
|
|
|
785
|
-
options.merge! :planner_model => self.class, :method_name => 'loops'
|
|
786
|
-
_, planning_options = PlanningLoop.filter_options(options)
|
|
787
|
-
|
|
788
889
|
loop_id = Planner.next_id
|
|
789
890
|
if !@stack.empty?
|
|
790
891
|
loop_id = "#{@stack.last[1]}_#{loop_id}"
|
|
791
892
|
end
|
|
893
|
+
loop_method = FreeMethod.new 'loops', {}, lambda(&block)
|
|
894
|
+
|
|
895
|
+
options[:planner_model] = self.class
|
|
896
|
+
options[:planning_method] = loop_method
|
|
897
|
+
_, planning_options = PlanningLoop.filter_options(options)
|
|
792
898
|
planning_options[:id] = loop_id
|
|
793
899
|
planning_options[:reuse] = false
|
|
794
|
-
|
|
900
|
+
loop_method.options.merge!(planning_options)
|
|
795
901
|
|
|
796
902
|
options[:method_options] ||= {}
|
|
797
903
|
options[:method_options].merge!(arguments || {})
|
|
798
|
-
options[:method_options][:id] =
|
|
904
|
+
options[:method_options][:id] = loop_method.id
|
|
799
905
|
PlanningLoop.new(options)
|
|
800
906
|
end
|
|
801
907
|
end
|