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.
Files changed (236) hide show
  1. data/History.txt +7 -5
  2. data/Manifest.txt +91 -16
  3. data/README.txt +24 -24
  4. data/Rakefile +92 -64
  5. data/app/config/app.yml +42 -43
  6. data/app/config/init.rb +26 -0
  7. data/benchmark/alloc_misc.rb +123 -0
  8. data/benchmark/discovery_latency.rb +67 -0
  9. data/benchmark/garbage_collection.rb +48 -0
  10. data/benchmark/genom.rb +31 -0
  11. data/benchmark/transactions.rb +62 -0
  12. data/bin/roby +1 -1
  13. data/bin/roby-log +16 -6
  14. data/doc/guide/.gitignore +2 -0
  15. data/doc/guide/config.yaml +34 -0
  16. data/doc/guide/ext/init.rb +14 -0
  17. data/doc/guide/ext/previous_next.rb +40 -0
  18. data/doc/guide/ext/rdoc_links.rb +33 -0
  19. data/doc/guide/index.rdoc +16 -0
  20. data/doc/guide/overview.rdoc +62 -0
  21. data/doc/guide/plan_modifications.rdoc +67 -0
  22. data/doc/guide/src/abstraction/achieve_with.page +8 -0
  23. data/doc/guide/src/abstraction/forwarding.page +8 -0
  24. data/doc/guide/src/abstraction/hierarchy.page +19 -0
  25. data/doc/guide/src/abstraction/index.page +28 -0
  26. data/doc/guide/src/abstraction/task_models.page +13 -0
  27. data/doc/guide/src/basics.template +6 -0
  28. data/doc/guide/src/basics/app.page +139 -0
  29. data/doc/guide/src/basics/code_examples.page +33 -0
  30. data/doc/guide/src/basics/dry.page +69 -0
  31. data/doc/guide/src/basics/errors.page +443 -0
  32. data/doc/guide/src/basics/events.page +179 -0
  33. data/doc/guide/src/basics/hierarchy.page +275 -0
  34. data/doc/guide/src/basics/index.page +11 -0
  35. data/doc/guide/src/basics/log_replay/goForward_1.png +0 -0
  36. data/doc/guide/src/basics/log_replay/goForward_2.png +0 -0
  37. data/doc/guide/src/basics/log_replay/goForward_3.png +0 -0
  38. data/doc/guide/src/basics/log_replay/goForward_4.png +0 -0
  39. data/doc/guide/src/basics/log_replay/goForward_5.png +0 -0
  40. data/doc/guide/src/basics/log_replay/hierarchy_error_1.png +0 -0
  41. data/doc/guide/src/basics/log_replay/hierarchy_error_2.png +0 -0
  42. data/doc/guide/src/basics/log_replay/hierarchy_error_3.png +0 -0
  43. data/doc/guide/src/basics/log_replay/plan_repair_1.png +0 -0
  44. data/doc/guide/src/basics/log_replay/plan_repair_2.png +0 -0
  45. data/doc/guide/src/basics/log_replay/plan_repair_3.png +0 -0
  46. data/doc/guide/src/basics/log_replay/plan_repair_4.png +0 -0
  47. data/doc/guide/src/basics/log_replay/roby_log_main_window.png +0 -0
  48. data/doc/guide/src/basics/log_replay/roby_log_relation_window.png +0 -0
  49. data/doc/guide/src/basics/log_replay/roby_replay_event_representation.png +0 -0
  50. data/doc/guide/src/basics/plan_objects.page +71 -0
  51. data/doc/guide/src/basics/relations_display.page +203 -0
  52. data/doc/guide/src/basics/roby_cycle_overview.png +0 -0
  53. data/doc/guide/src/basics/shell.page +102 -0
  54. data/doc/guide/src/basics/summary.page +32 -0
  55. data/doc/guide/src/basics/tasks.page +357 -0
  56. data/doc/guide/src/basics_shell_header.txt +16 -0
  57. data/doc/guide/src/cycle/cycle-overview.png +0 -0
  58. data/doc/guide/src/cycle/cycle-overview.svg +208 -0
  59. data/doc/guide/src/cycle/error_handling.page +168 -0
  60. data/doc/guide/src/cycle/error_instantaneous_repair.png +0 -0
  61. data/doc/guide/src/cycle/error_instantaneous_repair.svg +1224 -0
  62. data/doc/guide/src/cycle/garbage_collection.page +10 -0
  63. data/doc/guide/src/cycle/index.page +23 -0
  64. data/doc/guide/src/cycle/propagation.page +154 -0
  65. data/doc/guide/src/cycle/propagation_diamond.png +0 -0
  66. data/doc/guide/src/cycle/propagation_diamond.svg +1279 -0
  67. data/doc/guide/src/default.css +319 -0
  68. data/doc/guide/src/default.template +74 -0
  69. data/doc/guide/src/htmldoc.metainfo +20 -0
  70. data/doc/guide/src/htmldoc.virtual +18 -0
  71. data/doc/guide/src/images/bodybg.png +0 -0
  72. data/doc/guide/src/images/contbg.png +0 -0
  73. data/doc/guide/src/images/footerbg.png +0 -0
  74. data/doc/guide/src/images/gradient1.png +0 -0
  75. data/doc/guide/src/images/gradient2.png +0 -0
  76. data/doc/guide/src/index.page +7 -0
  77. data/doc/guide/src/introduction/index.page +29 -0
  78. data/doc/guide/src/introduction/install.page +133 -0
  79. data/doc/{papers.rdoc → guide/src/introduction/publications.page} +5 -2
  80. data/doc/{videos.rdoc → guide/src/introduction/videos.page} +4 -2
  81. data/doc/guide/src/plugins/fault_tolerance.page +44 -0
  82. data/doc/guide/src/plugins/index.page +11 -0
  83. data/doc/guide/src/plugins/subsystems.page +45 -0
  84. data/doc/guide/src/relations/dependency.page +89 -0
  85. data/doc/guide/src/relations/index.page +12 -0
  86. data/doc/misc/update_github +24 -0
  87. data/doc/tutorials/02-GoForward.rdoc +3 -3
  88. data/ext/graph/graph.cc +46 -0
  89. data/lib/roby.rb +57 -22
  90. data/lib/roby/app.rb +132 -112
  91. data/lib/roby/app/plugins/rake.rb +21 -0
  92. data/lib/roby/app/rake.rb +0 -7
  93. data/lib/roby/app/run.rb +1 -1
  94. data/lib/roby/app/scripts/distributed.rb +1 -2
  95. data/lib/roby/app/scripts/generate/bookmarks.rb +1 -1
  96. data/lib/roby/app/scripts/results.rb +2 -1
  97. data/lib/roby/app/scripts/run.rb +6 -2
  98. data/lib/roby/app/scripts/shell.rb +11 -11
  99. data/lib/roby/config.rb +1 -1
  100. data/lib/roby/decision_control.rb +62 -3
  101. data/lib/roby/distributed.rb +4 -0
  102. data/lib/roby/distributed/base.rb +8 -0
  103. data/lib/roby/distributed/communication.rb +12 -8
  104. data/lib/roby/distributed/connection_space.rb +61 -44
  105. data/lib/roby/distributed/distributed_object.rb +1 -1
  106. data/lib/roby/distributed/notifications.rb +22 -30
  107. data/lib/roby/distributed/peer.rb +13 -8
  108. data/lib/roby/distributed/proxy.rb +5 -5
  109. data/lib/roby/distributed/subscription.rb +4 -4
  110. data/lib/roby/distributed/transaction.rb +3 -3
  111. data/lib/roby/event.rb +176 -110
  112. data/lib/roby/exceptions.rb +12 -4
  113. data/lib/roby/execution_engine.rb +1604 -0
  114. data/lib/roby/external_process_task.rb +225 -0
  115. data/lib/roby/graph.rb +0 -6
  116. data/lib/roby/interface.rb +221 -137
  117. data/lib/roby/log/console.rb +5 -3
  118. data/lib/roby/log/data_stream.rb +94 -16
  119. data/lib/roby/log/dot.rb +8 -8
  120. data/lib/roby/log/event_stream.rb +13 -3
  121. data/lib/roby/log/file.rb +43 -18
  122. data/lib/roby/log/gui/basic_display_ui.rb +89 -0
  123. data/lib/roby/log/gui/chronicle_view_ui.rb +90 -0
  124. data/lib/roby/log/gui/data_displays.rb +4 -5
  125. data/lib/roby/log/gui/data_displays_ui.rb +146 -0
  126. data/lib/roby/log/gui/relations.rb +18 -18
  127. data/lib/roby/log/gui/relations_ui.rb +120 -0
  128. data/lib/roby/log/gui/relations_view_ui.rb +144 -0
  129. data/lib/roby/log/gui/replay.rb +41 -13
  130. data/lib/roby/log/gui/replay_controls.rb +3 -0
  131. data/lib/roby/log/gui/replay_controls.ui +133 -110
  132. data/lib/roby/log/gui/replay_controls_ui.rb +249 -0
  133. data/lib/roby/log/hooks.rb +19 -18
  134. data/lib/roby/log/logger.rb +7 -6
  135. data/lib/roby/log/notifications.rb +4 -4
  136. data/lib/roby/log/plan_rebuilder.rb +20 -22
  137. data/lib/roby/log/relations.rb +44 -16
  138. data/lib/roby/log/server.rb +1 -4
  139. data/lib/roby/log/timings.rb +88 -19
  140. data/lib/roby/plan-object.rb +135 -11
  141. data/lib/roby/plan.rb +408 -224
  142. data/lib/roby/planning/loops.rb +32 -25
  143. data/lib/roby/planning/model.rb +157 -51
  144. data/lib/roby/planning/task.rb +47 -20
  145. data/lib/roby/query.rb +128 -92
  146. data/lib/roby/relations.rb +254 -136
  147. data/lib/roby/relations/conflicts.rb +6 -9
  148. data/lib/roby/relations/dependency.rb +358 -0
  149. data/lib/roby/relations/ensured.rb +0 -1
  150. data/lib/roby/relations/error_handling.rb +0 -1
  151. data/lib/roby/relations/events.rb +0 -2
  152. data/lib/roby/relations/executed_by.rb +26 -11
  153. data/lib/roby/relations/planned_by.rb +14 -14
  154. data/lib/roby/robot.rb +46 -0
  155. data/lib/roby/schedulers/basic.rb +34 -0
  156. data/lib/roby/standalone.rb +4 -0
  157. data/lib/roby/standard_errors.rb +21 -15
  158. data/lib/roby/state/events.rb +5 -4
  159. data/lib/roby/support.rb +107 -6
  160. data/lib/roby/task-operations.rb +23 -19
  161. data/lib/roby/task.rb +522 -148
  162. data/lib/roby/task_index.rb +80 -0
  163. data/lib/roby/test/common.rb +283 -44
  164. data/lib/roby/test/distributed.rb +53 -37
  165. data/lib/roby/test/testcase.rb +9 -204
  166. data/lib/roby/test/tools.rb +3 -3
  167. data/lib/roby/transactions.rb +154 -111
  168. data/lib/roby/transactions/proxy.rb +40 -7
  169. data/manifest.xml +20 -0
  170. data/plugins/fault_injection/README.txt +0 -3
  171. data/plugins/fault_injection/Rakefile +2 -8
  172. data/plugins/fault_injection/app.rb +1 -1
  173. data/plugins/fault_injection/fault_injection.rb +3 -3
  174. data/plugins/fault_injection/test/test_fault_injection.rb +19 -25
  175. data/plugins/subsystems/README.txt +0 -3
  176. data/plugins/subsystems/Rakefile +2 -7
  177. data/plugins/subsystems/app.rb +27 -16
  178. data/plugins/subsystems/test/app/config/init.rb +3 -0
  179. data/plugins/subsystems/test/app/planners/main.rb +1 -1
  180. data/plugins/subsystems/test/app/tasks/services.rb +1 -1
  181. data/plugins/subsystems/test/test_subsystems.rb +23 -16
  182. data/test/distributed/test_communication.rb +32 -15
  183. data/test/distributed/test_connection.rb +28 -26
  184. data/test/distributed/test_execution.rb +59 -54
  185. data/test/distributed/test_mixed_plan.rb +34 -34
  186. data/test/distributed/test_plan_notifications.rb +26 -26
  187. data/test/distributed/test_protocol.rb +57 -48
  188. data/test/distributed/test_query.rb +11 -7
  189. data/test/distributed/test_remote_plan.rb +71 -71
  190. data/test/distributed/test_transaction.rb +50 -47
  191. data/test/mockups/external_process +28 -0
  192. data/test/planning/test_loops.rb +163 -119
  193. data/test/planning/test_model.rb +3 -3
  194. data/test/planning/test_task.rb +27 -7
  195. data/test/relations/test_conflicts.rb +3 -3
  196. data/test/relations/test_dependency.rb +324 -0
  197. data/test/relations/test_ensured.rb +2 -2
  198. data/test/relations/test_executed_by.rb +94 -19
  199. data/test/relations/test_planned_by.rb +11 -9
  200. data/test/suite_core.rb +6 -3
  201. data/test/suite_distributed.rb +1 -0
  202. data/test/suite_planning.rb +1 -0
  203. data/test/suite_relations.rb +2 -2
  204. data/test/tasks/test_external_process.rb +126 -0
  205. data/test/{test_thread_task.rb → tasks/test_thread_task.rb} +17 -20
  206. data/test/test_bgl.rb +21 -1
  207. data/test/test_event.rb +229 -155
  208. data/test/test_exceptions.rb +79 -80
  209. data/test/test_execution_engine.rb +987 -0
  210. data/test/test_gui.rb +1 -1
  211. data/test/test_interface.rb +11 -5
  212. data/test/test_log.rb +18 -7
  213. data/test/test_log_server.rb +1 -0
  214. data/test/test_plan.rb +229 -395
  215. data/test/test_query.rb +193 -35
  216. data/test/test_relations.rb +88 -8
  217. data/test/test_state.rb +55 -37
  218. data/test/test_support.rb +1 -1
  219. data/test/test_task.rb +371 -218
  220. data/test/test_testcase.rb +32 -16
  221. data/test/test_transactions.rb +211 -170
  222. data/test/test_transactions_proxy.rb +37 -19
  223. metadata +169 -71
  224. data/.gitignore +0 -29
  225. data/doc/styles/allison.css +0 -314
  226. data/doc/styles/allison.js +0 -316
  227. data/doc/styles/allison.rb +0 -276
  228. data/doc/styles/jamis.rb +0 -593
  229. data/lib/roby/control.rb +0 -746
  230. data/lib/roby/executives/simple.rb +0 -30
  231. data/lib/roby/propagation.rb +0 -562
  232. data/lib/roby/relations/hierarchy.rb +0 -239
  233. data/lib/roby/transactions/updates.rb +0 -139
  234. data/test/relations/test_hierarchy.rb +0 -158
  235. data/test/test_control.rb +0 -399
  236. data/test/test_propagation.rb +0 -210
@@ -3,9 +3,12 @@
3
3
  # [Roby] core namespace for the Roby kernel
4
4
  # [Roby::Distributed] parts that are very specific to distributed plan management
5
5
  # [Roby::Planning] basic tools for plan generation
6
- # [Roby::Transactions] implementation of transactions
7
- # [Roby::EventStructure] event relations
8
- # [Roby::TaskStructure] task relations
6
+ # [Roby::Transactions] implementation of transactions. Transactions represent a
7
+ # change in the main plan, and can be distributed among different plan managers.
8
+ # [Roby::EventStructure] main namespace for event relations. The methods listed
9
+ # in the documentation of EventStructure are actually methods of Roby::EventGenerator
10
+ # [Roby::TaskStructure] main namespace for task relations. The methods listed in
11
+ # the documentation of TaskStructure are actually methods of Roby::Task
9
12
  module Roby
10
13
  class BasicObject; end
11
14
  class PlanObject < BasicObject; end
@@ -15,28 +18,60 @@ module Roby
15
18
  class Task < PlanObject; end
16
19
  end
17
20
 
18
- require 'roby/support'
19
- require 'roby/task'
20
- require 'roby/event'
21
- require 'roby/standard_errors'
21
+ require 'drb'
22
+ require 'utilrb/weakref'
23
+ require 'pp'
24
+ require 'thread'
25
+ require 'set'
26
+ require 'yaml'
27
+ require 'utilrb/value_set'
28
+ require 'utilrb/object/attribute'
29
+ require 'utilrb/module/ancestor_p'
30
+ require 'utilrb/kernel/options'
31
+ require 'utilrb/module/attr_enumerable'
32
+ require 'utilrb/module/attr_predicate'
33
+ require 'utilrb/module/inherited_enumerable'
34
+ require 'utilrb/module/include'
35
+ require 'utilrb/kernel/arity'
36
+ require 'utilrb/kernel/swap'
37
+ require 'utilrb/exception/full_message'
38
+ require 'utilrb/unbound_method/call'
22
39
 
23
- require 'roby/plan'
24
- require 'roby/query'
25
- require 'roby/control'
26
- require 'roby/decision_control'
40
+ require 'roby/config.rb'
41
+ require 'roby/support.rb'
42
+ require 'roby/basic_object.rb'
43
+ require 'roby/standard_errors.rb'
44
+ require 'roby/exceptions.rb'
45
+ require 'roby_bgl'
46
+ require 'roby/graph.rb'
47
+ require 'roby/relations.rb'
27
48
 
28
- require 'roby/propagation'
29
- require 'roby/relations/events'
30
- require 'roby/relations/hierarchy'
31
- require 'roby/relations/influence'
32
- require 'roby/relations/planned_by'
33
- require 'roby/relations/executed_by'
34
- require 'roby/relations/ensured'
49
+ require 'roby/plan-object.rb'
50
+ require 'roby/event.rb'
51
+ require 'roby/task.rb'
52
+ require 'roby/task-operations.rb'
35
53
 
36
- require 'roby/state'
37
- require 'roby/interface'
54
+ require 'roby/relations/conflicts.rb'
55
+ require 'roby/relations/ensured.rb'
56
+ require 'roby/relations/error_handling.rb'
57
+ require 'roby/relations/events.rb'
58
+ require 'roby/relations/executed_by.rb'
59
+ require 'roby/relations/dependency.rb'
60
+ require 'roby/relations/influence.rb'
61
+ require 'roby/relations/planned_by.rb'
38
62
 
39
- require 'roby/distributed/protocol'
63
+ require 'roby/task_index.rb'
64
+ require 'roby/plan.rb'
65
+ require 'roby/transactions/proxy.rb'
66
+ require 'roby/transactions.rb'
67
+ require 'roby/query.rb'
40
68
 
41
- require 'roby/app'
69
+ require 'roby/distributed/base'
70
+ require 'roby/decision_control.rb'
71
+ require 'roby/execution_engine.rb'
72
+ require 'roby/app.rb'
73
+
74
+ require 'roby/robot.rb'
75
+ require 'roby/planning.rb'
76
+ require 'roby/state.rb'
42
77
 
@@ -1,16 +1,5 @@
1
- require 'roby'
2
- require 'roby/distributed'
3
- require 'roby/planning'
4
- require 'roby/log'
5
- require 'roby/log/event_stream'
6
-
7
- require 'roby/robot'
8
- require 'yaml'
9
-
1
+ require 'singleton'
10
2
  module Roby
11
- # Returns the only one Application object
12
- def self.app; Application.instance end
13
-
14
3
  # = Roby Applications
15
4
  #
16
5
  # There is one and only one Application object, which holds mainly the
@@ -56,6 +45,9 @@ module Roby
56
45
  # Roby::Test::TestCase for a description of Roby-specific tests.
57
46
  class Application
58
47
  include Singleton
48
+
49
+ # A set of planners declared in this application
50
+ attr_reader :planners
59
51
 
60
52
  # The plain option hash saved in config/app.yml
61
53
  attr_reader :options
@@ -70,6 +62,9 @@ module Roby
70
62
  # dir:: the log directory. Uses APP_DIR/log if not set
71
63
  # filter_backtraces:: true if the framework code should be removed from the error backtraces
72
64
  attr_reader :log
65
+
66
+ # ExecutionEngine setup
67
+ attr_reader :engine
73
68
 
74
69
  # A [name, dir, file, module] array of available plugins, where 'name'
75
70
  # is the plugin name, 'dir' the directory in which it is installed,
@@ -88,12 +83,10 @@ module Roby
88
83
  # detected
89
84
  attr_reader :droby
90
85
 
91
- # Configuration of the control loop
92
- # abort_on_exception:: if the control loop should abort if an uncaught task or event exception is received. Defaults
93
- # to false
94
- # abort_on_application_exception:: if the control should abort if an uncaught application exception (not originating
95
- # from a task or event) is caught. Defaults to true.
96
- attr_reader :control
86
+ # If true, abort if an unhandled exception is found
87
+ attr_predicate :abort_on_exception, true
88
+ # If true, abort if an application exception is found
89
+ attr_predicate :abort_on_application_exception, true
97
90
 
98
91
  # An array of directories in which to search for plugins
99
92
  attr_reader :plugin_dirs
@@ -117,13 +110,13 @@ module Roby
117
110
  @log = Hash['events' => 'stats', 'levels' => Hash.new, 'filter_backtraces' => true]
118
111
  @discovery = Hash.new
119
112
  @droby = Hash['period' => 0.5, 'max_errors' => 1]
120
- @control = Hash[ 'abort_on_exception' => false,
121
- 'abort_on_application_exception' => true ]
113
+ @engine = Hash.new
122
114
 
123
115
  @automatic_testing = true
124
116
  @testing_keep_logs = false
125
117
 
126
118
  @plugin_dirs = []
119
+ @planners = []
127
120
  end
128
121
 
129
122
  # Adds +dir+ in the list of directories searched for plugins
@@ -207,7 +200,7 @@ module Roby
207
200
 
208
201
  @options = options
209
202
 
210
- load_option_hashes(options, %w{log control discovery droby})
203
+ load_option_hashes(options, %w{log engine discovery droby})
211
204
  call_plugins(:load, self, options)
212
205
  end
213
206
 
@@ -349,7 +342,7 @@ module Roby
349
342
 
350
343
  # Set up log levels
351
344
  log['levels'].each do |name, value|
352
- name = name.camelize
345
+ name = name.camelcase(true)
353
346
  if value =~ /^(\w+):(.+)$/
354
347
  level, file = $1, $2
355
348
  level = Logger.const_get(level)
@@ -367,19 +360,18 @@ module Roby
367
360
  new_logger.level = level
368
361
  new_logger.formatter = Roby.logger.formatter
369
362
 
370
- if (mod = name.constantize rescue nil)
371
- if robot_name
372
- new_logger.progname = "#{name} #{robot_name}"
373
- else
374
- new_logger.progname = name
375
- end
376
- mod.logger = new_logger
377
- end
363
+ mod = Kernel.constant(name)
364
+ if robot_name
365
+ new_logger.progname = "#{name} #{robot_name}"
366
+ else
367
+ new_logger.progname = name
368
+ end
369
+ mod.logger = new_logger
378
370
  end
379
371
  end
380
372
 
381
373
  def setup_dirs
382
- Dir.mkdir(log_dir) unless File.exists?(log_dir)
374
+ FileUtils.mkdir_p(log_dir) unless File.exists?(log_dir)
383
375
  if File.directory?(libdir = File.join(APP_DIR, 'lib'))
384
376
  if !$LOAD_PATH.include?(libdir)
385
377
  $LOAD_PATH.unshift File.join(APP_DIR, 'lib')
@@ -397,22 +389,17 @@ module Roby
397
389
  def require_models
398
390
  # Require all common task models and the task models specific to
399
391
  # this robot
400
- require_dir(File.join(APP_DIR, 'tasks'))
401
- require_robotdir(File.join(APP_DIR, 'tasks', 'ROBOT'))
392
+ list_dir('tasks') { |p| require(p) }
393
+ list_robotdir('tasks', 'ROBOT') { |p| require(p) }
402
394
 
403
395
  # Load robot-specific configuration
404
- planner_dir = File.join(APP_DIR, 'planners')
405
- models_search = [planner_dir]
396
+ models_search = ['planners']
406
397
  if robot_name
407
- load_robotfile(File.join(APP_DIR, 'config', "ROBOT.rb"))
408
-
409
- models_search << File.join(planner_dir, robot_name) << File.join(planner_dir, robot_type)
410
- if !require_robotfile(File.join(APP_DIR, 'planners', 'ROBOT', 'main.rb'))
411
- require File.join(APP_DIR, "planners", "main")
412
- end
413
- else
414
- require File.join(APP_DIR, "planners", "main")
415
- end
398
+ models_search << File.join('planners', robot_name) << File.join('planners', robot_type)
399
+ file = robotfile('planners', 'ROBOT', 'main.rb')
400
+ end
401
+ file ||= File.join("planners", "main")
402
+ require file if File.file?(file)
416
403
 
417
404
  # Load the other planners
418
405
  models_search.each do |base_dir|
@@ -423,10 +410,19 @@ module Roby
423
410
  end
424
411
  end
425
412
  end
413
+
414
+ # Set up the loaded plugins
415
+ call_plugins(:require_models, self)
426
416
  end
427
417
 
428
418
  def setup
419
+ if !Roby.plan
420
+ Roby.instance_variable_set :@plan, Plan.new
421
+ end
422
+
429
423
  reset
424
+ require 'roby/planning'
425
+ require 'roby/interface'
430
426
 
431
427
  $LOAD_PATH.unshift(APP_DIR) unless $LOAD_PATH.include?(APP_DIR)
432
428
 
@@ -448,14 +444,21 @@ module Roby
448
444
  Object.const_set(:State, Roby::State)
449
445
  end
450
446
 
447
+ # Set up the loaded plugins
448
+ call_plugins(:setup, self)
449
+
451
450
  require_models
452
451
 
452
+ if file = robotfile(APP_DIR, 'config', "ROBOT.rb")
453
+ load file
454
+ end
455
+
456
+
453
457
  # MainPlanner is always included in the planner list
454
- Roby.control.planners << MainPlanner
458
+ if defined? MainPlanner
459
+ self.planners << MainPlanner
460
+ end
455
461
 
456
- # Set up the loaded plugins
457
- call_plugins(:setup, self)
458
-
459
462
  # If we are in test mode, import the test extensions from plugins
460
463
  if testing?
461
464
  require 'roby/test/testcase'
@@ -468,6 +471,8 @@ module Roby
468
471
  end
469
472
 
470
473
  def run(&block)
474
+ setup_global_singletons
475
+
471
476
  # Set up dRoby, setting an Interface object as front server, for shell access
472
477
  host = droby['host'] || ""
473
478
  if host !~ /:\d+$/
@@ -476,9 +481,9 @@ module Roby
476
481
 
477
482
  if single? || !robot_name
478
483
  host =~ /:(\d+)$/
479
- DRb.start_service "druby://:#{$1 || '0'}", Interface.new(Roby.control)
484
+ DRb.start_service "druby://:#{$1 || '0'}", Interface.new(Roby.engine)
480
485
  else
481
- DRb.start_service "druby://#{host}", Interface.new(Roby.control)
486
+ DRb.start_service "druby://#{host}", Interface.new(Roby.engine)
482
487
  droby_config = { :ring_discovery => !!discovery['ring'],
483
488
  :name => robot_name,
484
489
  :plan => Roby.plan,
@@ -492,7 +497,7 @@ module Roby
492
497
  if discovery['ring']
493
498
  Roby::Distributed.publish discovery['ring']
494
499
  end
495
- Roby::Control.every(discovery['period'] || 0.5) do
500
+ Roby.every(discovery['period'] || 0.5) do
496
501
  Roby::Distributed.state.start_neighbour_discovery
497
502
  end
498
503
  end
@@ -500,27 +505,18 @@ module Roby
500
505
  @robot_name ||= 'common'
501
506
  @robot_type ||= 'common'
502
507
 
503
- control_config = self.control
504
- control = Roby.control
505
- options = { :detach => true, :cycle => control_config['cycle'] || 0.1 }
508
+ engine_config = self.engine
509
+ engine = Roby.engine
510
+ options = { :cycle => engine_config['cycle'] || 0.1 }
506
511
 
507
- # Add an executive if one is defined
508
- if control_config['executive']
509
- self.executive = control_config['executive']
510
- end
511
-
512
512
  if log['events']
513
513
  require 'roby/log/file'
514
514
  logfile = File.join(log_dir, robot_name)
515
- logger = Roby::Log::FileLogger.new(logfile)
515
+ logger = Roby::Log::FileLogger.new(logfile, :plugins => plugins.map { |n, _| n })
516
516
  logger.stats_mode = log['events'] == 'stats'
517
517
  Roby::Log.add_logger logger
518
518
  end
519
- control.abort_on_exception =
520
- control_config['abort_on_exception']
521
- control.abort_on_application_exception =
522
- control_config['abort_on_application_exception']
523
- control.run options
519
+ engine.run options
524
520
 
525
521
  plugins = self.plugins.map { |_, mod| mod if mod.respond_to?(:run) }.compact
526
522
  run_plugins(plugins, &block)
@@ -533,11 +529,11 @@ module Roby
533
529
  end
534
530
  end
535
531
  def run_plugins(mods, &block)
536
- control = Roby.control
532
+ engine = Roby.engine
537
533
 
538
534
  if mods.empty?
539
535
  yield
540
- control.join
536
+ engine.join
541
537
  else
542
538
  mod = mods.shift
543
539
  mod.run(self) do
@@ -546,30 +542,15 @@ module Roby
546
542
  end
547
543
 
548
544
  rescue Exception => e
549
- if Roby.control.running?
550
- control.quit
551
- control.join
545
+ if Roby.engine.running?
546
+ engine.quit
547
+ engine.join
552
548
  raise e, e.message, e.backtrace
553
549
  else
554
550
  raise
555
551
  end
556
552
  end
557
553
 
558
- attr_reader :executive
559
-
560
- def executive=(name)
561
- if executive
562
- Control.event_processing.delete(executive.method(:initial_events))
563
- @executive = nil
564
- end
565
- return unless name
566
-
567
- full_name = "roby/executives/#{name}"
568
- require full_name
569
- @executive = full_name.camelize.constantize.new
570
- Control.event_processing << executive.method(:initial_events)
571
- end
572
-
573
554
  def stop; call_plugins(:stop, self) end
574
555
 
575
556
  DISCOVERY_TEMPLATE = [:droby, nil, nil]
@@ -583,7 +564,7 @@ module Roby
583
564
  Thread.abort_on_exception = true
584
565
 
585
566
  if !File.exists?(log_dir)
586
- Dir.mkdir(log_dir)
567
+ FileUtils.mkdir_p(log_dir)
587
568
  end
588
569
 
589
570
  unless single? || !discovery['tuplespace']
@@ -678,52 +659,49 @@ module Roby
678
659
  call_plugins(:stop_server, self)
679
660
  end
680
661
 
681
- # Require all files in +dirname+
682
- def require_dir(dirname)
662
+ def list_dir(*path)
663
+ if !block_given?
664
+ return enum_for(:list_dir, *path)
665
+ end
666
+
667
+ dirname = File.join(*path)
683
668
  Dir.new(dirname).each do |file|
684
669
  file = File.join(dirname, file)
685
- file = file.gsub(/^#{Regexp.quote(APP_DIR)}\//, '')
686
- require file if file =~ /\.rb$/ && File.file?(file)
670
+ if file =~ /\.rb$/ && File.file?(file)
671
+ file = file.gsub(/^#{Regexp.quote(APP_DIR)}\//, '')
672
+ yield(file)
673
+ end
687
674
  end
688
- end
675
+ end
689
676
 
690
677
  # Require all files in the directories matching +pattern+. If +pattern+
691
678
  # contains the word ROBOT, it is replaced by -- in order -- the robot
692
679
  # name and then the robot type
693
- def require_robotdir(pattern)
680
+ def list_robotdir(*path, &block)
681
+ if !block_given?
682
+ return enum_for(:list_robotdir, *path)
683
+ end
684
+
694
685
  return unless robot_name && robot_type
695
686
 
696
- [robot_name, robot_type].each do |name|
687
+ pattern = File.expand_path(File.join(*path), APP_DIR)
688
+ [robot_name, robot_type].uniq.each do |name|
697
689
  dirname = pattern.gsub(/ROBOT/, name)
698
- require_dir(dirname) if File.directory?(dirname)
690
+ list_dir(dirname, &block) if File.directory?(dirname)
699
691
  end
700
692
  end
701
693
 
702
- # Loads the first file found matching +pattern+
703
- #
704
- # See #require_robotfile
705
- def load_robotfile(pattern)
706
- require_robotfile(pattern, :load)
707
- end
708
-
709
- # Requires or loads (according to the value of +method+) the first file
710
- # found matching +pattern+. +pattern+ can contain the word ROBOT, in
711
- # which case the file is first checked against the robot name and then
712
- # against the robot type
713
- def require_robotfile(pattern, method = :require)
694
+ def robotfile(*path) # :nodoc
714
695
  return unless robot_name && robot_type
715
696
 
697
+ pattern = File.join(*path)
716
698
  robot_config = pattern.gsub(/ROBOT/, robot_name)
717
699
  if File.file?(robot_config)
718
- Kernel.send(method, robot_config)
719
- true
700
+ robot_config
720
701
  else
721
702
  robot_config = pattern.gsub(/ROBOT/, robot_type)
722
703
  if File.file?(robot_config)
723
- Kernel.send(method, robot_config)
724
- true
725
- else
726
- false
704
+ robot_config
727
705
  end
728
706
  end
729
707
  end
@@ -738,6 +716,34 @@ module Roby
738
716
  def single?; @single || discovery.empty? end
739
717
  def single; @single = true end
740
718
 
719
+ def setup_global_singletons
720
+ if !Roby.plan
721
+ Roby.instance_variable_set :@plan, Plan.new
722
+ end
723
+
724
+ if !Roby.engine && Roby.plan.engine
725
+ # This checks coherence with Roby.control, and sets it
726
+ # accordingly
727
+ Roby.engine = Roby.plan.engine
728
+ elsif !Roby.control
729
+ Roby.control = DecisionControl.new
730
+ end
731
+
732
+ if !Roby.engine
733
+ Roby.engine = ExecutionEngine.new(Roby.plan, Roby.control)
734
+ end
735
+
736
+ if Roby.control != Roby.engine.control
737
+ raise "inconsistency between Roby.control and Roby.engine.control"
738
+ elsif Roby.engine != Roby.plan.engine
739
+ raise "inconsistency between Roby.engine and Roby.plan.engine"
740
+ end
741
+
742
+ if !Roby.engine.scheduler && Roby.scheduler
743
+ Roby.engine.scheduler = Roby.scheduler
744
+ end
745
+ end
746
+
741
747
  # Guesses the type of +filename+ if it is a source suitable for
742
748
  # data display in this application
743
749
  def data_streams_of(filenames)
@@ -857,6 +863,20 @@ module Roby
857
863
  end
858
864
  end
859
865
 
866
+ @app = Application.instance
867
+ class << self
868
+ # The one and only Application object
869
+ attr_reader :app
870
+
871
+ # The scheduler object to be used during execution. See
872
+ # ExecutionEngine#scheduler.
873
+ #
874
+ # This is only used during the configuration of the application, and
875
+ # not afterwards. It is also possible to set per-engine through
876
+ # ExecutionEngine#scheduler=
877
+ attr_accessor :scheduler
878
+ end
879
+
860
880
  # Load the plugins 'main' files
861
881
  Roby.app.plugin_dir File.join(ROBY_ROOT_DIR, 'plugins')
862
882
  if plugin_path = ENV['ROBY_PLUGIN_PATH']