roby 0.7

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 (240) hide show
  1. data/.gitignore +29 -0
  2. data/History.txt +4 -0
  3. data/License-fr.txt +519 -0
  4. data/License.txt +515 -0
  5. data/Manifest.txt +245 -0
  6. data/NOTES +4 -0
  7. data/README.txt +163 -0
  8. data/Rakefile +161 -0
  9. data/TODO.txt +146 -0
  10. data/app/README.txt +24 -0
  11. data/app/Rakefile +8 -0
  12. data/app/config/ROBOT.rb +5 -0
  13. data/app/config/app.yml +91 -0
  14. data/app/config/init.rb +7 -0
  15. data/app/config/roby.yml +3 -0
  16. data/app/controllers/.gitattributes +0 -0
  17. data/app/controllers/ROBOT.rb +2 -0
  18. data/app/data/.gitattributes +0 -0
  19. data/app/planners/ROBOT/main.rb +6 -0
  20. data/app/planners/main.rb +5 -0
  21. data/app/scripts/distributed +3 -0
  22. data/app/scripts/generate/bookmarks +3 -0
  23. data/app/scripts/replay +3 -0
  24. data/app/scripts/results +3 -0
  25. data/app/scripts/run +3 -0
  26. data/app/scripts/server +3 -0
  27. data/app/scripts/shell +3 -0
  28. data/app/scripts/test +3 -0
  29. data/app/tasks/.gitattributes +0 -0
  30. data/app/tasks/ROBOT/.gitattributes +0 -0
  31. data/bin/roby +210 -0
  32. data/bin/roby-log +168 -0
  33. data/bin/roby-shell +25 -0
  34. data/doc/images/event_generalization.png +0 -0
  35. data/doc/images/exception_propagation_1.png +0 -0
  36. data/doc/images/exception_propagation_2.png +0 -0
  37. data/doc/images/exception_propagation_3.png +0 -0
  38. data/doc/images/exception_propagation_4.png +0 -0
  39. data/doc/images/exception_propagation_5.png +0 -0
  40. data/doc/images/replay_handler_error.png +0 -0
  41. data/doc/images/replay_handler_error_0.png +0 -0
  42. data/doc/images/replay_handler_error_1.png +0 -0
  43. data/doc/images/roby_cycle_overview.png +0 -0
  44. data/doc/images/roby_replay_02.png +0 -0
  45. data/doc/images/roby_replay_03.png +0 -0
  46. data/doc/images/roby_replay_04.png +0 -0
  47. data/doc/images/roby_replay_event_representation.png +0 -0
  48. data/doc/images/roby_replay_first_state.png +0 -0
  49. data/doc/images/roby_replay_relations.png +0 -0
  50. data/doc/images/roby_replay_startup.png +0 -0
  51. data/doc/images/task_event_generalization.png +0 -0
  52. data/doc/papers.rdoc +11 -0
  53. data/doc/styles/allison.css +314 -0
  54. data/doc/styles/allison.js +316 -0
  55. data/doc/styles/allison.rb +276 -0
  56. data/doc/styles/jamis.rb +593 -0
  57. data/doc/tutorials/01-GettingStarted.rdoc +86 -0
  58. data/doc/tutorials/02-GoForward.rdoc +220 -0
  59. data/doc/tutorials/03-PlannedPath.rdoc +268 -0
  60. data/doc/tutorials/04-EventPropagation.rdoc +236 -0
  61. data/doc/tutorials/05-ErrorHandling.rdoc +319 -0
  62. data/doc/tutorials/06-Overview.rdoc +40 -0
  63. data/doc/videos.rdoc +69 -0
  64. data/ext/droby/dump.cc +175 -0
  65. data/ext/droby/extconf.rb +3 -0
  66. data/ext/graph/algorithm.cc +746 -0
  67. data/ext/graph/extconf.rb +7 -0
  68. data/ext/graph/graph.cc +529 -0
  69. data/ext/graph/graph.hh +183 -0
  70. data/ext/graph/iterator_sequence.hh +102 -0
  71. data/ext/graph/undirected_dfs.hh +226 -0
  72. data/ext/graph/undirected_graph.hh +421 -0
  73. data/lib/roby.rb +41 -0
  74. data/lib/roby/app.rb +870 -0
  75. data/lib/roby/app/rake.rb +56 -0
  76. data/lib/roby/app/run.rb +14 -0
  77. data/lib/roby/app/scripts/distributed.rb +13 -0
  78. data/lib/roby/app/scripts/generate/bookmarks.rb +162 -0
  79. data/lib/roby/app/scripts/replay.rb +31 -0
  80. data/lib/roby/app/scripts/results.rb +15 -0
  81. data/lib/roby/app/scripts/run.rb +26 -0
  82. data/lib/roby/app/scripts/server.rb +18 -0
  83. data/lib/roby/app/scripts/shell.rb +88 -0
  84. data/lib/roby/app/scripts/test.rb +40 -0
  85. data/lib/roby/basic_object.rb +151 -0
  86. data/lib/roby/config.rb +5 -0
  87. data/lib/roby/control.rb +747 -0
  88. data/lib/roby/decision_control.rb +17 -0
  89. data/lib/roby/distributed.rb +32 -0
  90. data/lib/roby/distributed/base.rb +440 -0
  91. data/lib/roby/distributed/communication.rb +871 -0
  92. data/lib/roby/distributed/connection_space.rb +592 -0
  93. data/lib/roby/distributed/distributed_object.rb +206 -0
  94. data/lib/roby/distributed/drb.rb +62 -0
  95. data/lib/roby/distributed/notifications.rb +539 -0
  96. data/lib/roby/distributed/peer.rb +550 -0
  97. data/lib/roby/distributed/protocol.rb +529 -0
  98. data/lib/roby/distributed/proxy.rb +343 -0
  99. data/lib/roby/distributed/subscription.rb +311 -0
  100. data/lib/roby/distributed/transaction.rb +498 -0
  101. data/lib/roby/event.rb +897 -0
  102. data/lib/roby/exceptions.rb +234 -0
  103. data/lib/roby/executives/simple.rb +30 -0
  104. data/lib/roby/graph.rb +166 -0
  105. data/lib/roby/interface.rb +390 -0
  106. data/lib/roby/log.rb +3 -0
  107. data/lib/roby/log/chronicle.rb +303 -0
  108. data/lib/roby/log/console.rb +72 -0
  109. data/lib/roby/log/data_stream.rb +197 -0
  110. data/lib/roby/log/dot.rb +279 -0
  111. data/lib/roby/log/event_stream.rb +151 -0
  112. data/lib/roby/log/file.rb +340 -0
  113. data/lib/roby/log/gui/basic_display.ui +83 -0
  114. data/lib/roby/log/gui/chronicle.rb +26 -0
  115. data/lib/roby/log/gui/chronicle_view.rb +40 -0
  116. data/lib/roby/log/gui/chronicle_view.ui +70 -0
  117. data/lib/roby/log/gui/data_displays.rb +172 -0
  118. data/lib/roby/log/gui/data_displays.ui +155 -0
  119. data/lib/roby/log/gui/notifications.rb +26 -0
  120. data/lib/roby/log/gui/relations.rb +248 -0
  121. data/lib/roby/log/gui/relations.ui +123 -0
  122. data/lib/roby/log/gui/relations_view.rb +185 -0
  123. data/lib/roby/log/gui/relations_view.ui +149 -0
  124. data/lib/roby/log/gui/replay.rb +327 -0
  125. data/lib/roby/log/gui/replay_controls.rb +200 -0
  126. data/lib/roby/log/gui/replay_controls.ui +259 -0
  127. data/lib/roby/log/gui/runtime.rb +130 -0
  128. data/lib/roby/log/hooks.rb +185 -0
  129. data/lib/roby/log/logger.rb +202 -0
  130. data/lib/roby/log/notifications.rb +244 -0
  131. data/lib/roby/log/plan_rebuilder.rb +470 -0
  132. data/lib/roby/log/relations.rb +1056 -0
  133. data/lib/roby/log/server.rb +550 -0
  134. data/lib/roby/log/sqlite.rb +47 -0
  135. data/lib/roby/log/timings.rb +164 -0
  136. data/lib/roby/plan-object.rb +247 -0
  137. data/lib/roby/plan.rb +762 -0
  138. data/lib/roby/planning.rb +13 -0
  139. data/lib/roby/planning/loops.rb +302 -0
  140. data/lib/roby/planning/model.rb +906 -0
  141. data/lib/roby/planning/task.rb +151 -0
  142. data/lib/roby/propagation.rb +562 -0
  143. data/lib/roby/query.rb +619 -0
  144. data/lib/roby/relations.rb +583 -0
  145. data/lib/roby/relations/conflicts.rb +70 -0
  146. data/lib/roby/relations/ensured.rb +20 -0
  147. data/lib/roby/relations/error_handling.rb +23 -0
  148. data/lib/roby/relations/events.rb +9 -0
  149. data/lib/roby/relations/executed_by.rb +193 -0
  150. data/lib/roby/relations/hierarchy.rb +239 -0
  151. data/lib/roby/relations/influence.rb +10 -0
  152. data/lib/roby/relations/planned_by.rb +63 -0
  153. data/lib/roby/robot.rb +7 -0
  154. data/lib/roby/standard_errors.rb +218 -0
  155. data/lib/roby/state.rb +5 -0
  156. data/lib/roby/state/events.rb +221 -0
  157. data/lib/roby/state/information.rb +55 -0
  158. data/lib/roby/state/pos.rb +110 -0
  159. data/lib/roby/state/shapes.rb +32 -0
  160. data/lib/roby/state/state.rb +353 -0
  161. data/lib/roby/support.rb +92 -0
  162. data/lib/roby/task-operations.rb +182 -0
  163. data/lib/roby/task.rb +1618 -0
  164. data/lib/roby/test/common.rb +399 -0
  165. data/lib/roby/test/distributed.rb +214 -0
  166. data/lib/roby/test/tasks/empty_task.rb +9 -0
  167. data/lib/roby/test/tasks/goto.rb +36 -0
  168. data/lib/roby/test/tasks/simple_task.rb +23 -0
  169. data/lib/roby/test/testcase.rb +519 -0
  170. data/lib/roby/test/tools.rb +160 -0
  171. data/lib/roby/thread_task.rb +87 -0
  172. data/lib/roby/transactions.rb +462 -0
  173. data/lib/roby/transactions/proxy.rb +292 -0
  174. data/lib/roby/transactions/updates.rb +139 -0
  175. data/plugins/fault_injection/History.txt +4 -0
  176. data/plugins/fault_injection/README.txt +37 -0
  177. data/plugins/fault_injection/Rakefile +18 -0
  178. data/plugins/fault_injection/TODO.txt +0 -0
  179. data/plugins/fault_injection/app.rb +52 -0
  180. data/plugins/fault_injection/fault_injection.rb +89 -0
  181. data/plugins/fault_injection/test/test_fault_injection.rb +84 -0
  182. data/plugins/subsystems/README.txt +40 -0
  183. data/plugins/subsystems/Rakefile +18 -0
  184. data/plugins/subsystems/app.rb +171 -0
  185. data/plugins/subsystems/test/app/README +24 -0
  186. data/plugins/subsystems/test/app/Rakefile +8 -0
  187. data/plugins/subsystems/test/app/config/app.yml +71 -0
  188. data/plugins/subsystems/test/app/config/init.rb +9 -0
  189. data/plugins/subsystems/test/app/config/roby.yml +3 -0
  190. data/plugins/subsystems/test/app/planners/main.rb +20 -0
  191. data/plugins/subsystems/test/app/scripts/distributed +3 -0
  192. data/plugins/subsystems/test/app/scripts/replay +3 -0
  193. data/plugins/subsystems/test/app/scripts/results +3 -0
  194. data/plugins/subsystems/test/app/scripts/run +3 -0
  195. data/plugins/subsystems/test/app/scripts/server +3 -0
  196. data/plugins/subsystems/test/app/scripts/shell +3 -0
  197. data/plugins/subsystems/test/app/scripts/test +3 -0
  198. data/plugins/subsystems/test/app/tasks/services.rb +15 -0
  199. data/plugins/subsystems/test/test_subsystems.rb +71 -0
  200. data/test/distributed/test_communication.rb +178 -0
  201. data/test/distributed/test_connection.rb +282 -0
  202. data/test/distributed/test_execution.rb +373 -0
  203. data/test/distributed/test_mixed_plan.rb +341 -0
  204. data/test/distributed/test_plan_notifications.rb +238 -0
  205. data/test/distributed/test_protocol.rb +516 -0
  206. data/test/distributed/test_query.rb +102 -0
  207. data/test/distributed/test_remote_plan.rb +491 -0
  208. data/test/distributed/test_transaction.rb +463 -0
  209. data/test/mockups/tasks.rb +27 -0
  210. data/test/planning/test_loops.rb +380 -0
  211. data/test/planning/test_model.rb +427 -0
  212. data/test/planning/test_task.rb +106 -0
  213. data/test/relations/test_conflicts.rb +42 -0
  214. data/test/relations/test_ensured.rb +38 -0
  215. data/test/relations/test_executed_by.rb +149 -0
  216. data/test/relations/test_hierarchy.rb +158 -0
  217. data/test/relations/test_planned_by.rb +54 -0
  218. data/test/suite_core.rb +24 -0
  219. data/test/suite_distributed.rb +9 -0
  220. data/test/suite_planning.rb +3 -0
  221. data/test/suite_relations.rb +8 -0
  222. data/test/test_bgl.rb +508 -0
  223. data/test/test_control.rb +399 -0
  224. data/test/test_event.rb +894 -0
  225. data/test/test_exceptions.rb +592 -0
  226. data/test/test_interface.rb +37 -0
  227. data/test/test_log.rb +114 -0
  228. data/test/test_log_server.rb +132 -0
  229. data/test/test_plan.rb +584 -0
  230. data/test/test_propagation.rb +210 -0
  231. data/test/test_query.rb +266 -0
  232. data/test/test_relations.rb +180 -0
  233. data/test/test_state.rb +414 -0
  234. data/test/test_support.rb +16 -0
  235. data/test/test_task.rb +938 -0
  236. data/test/test_testcase.rb +122 -0
  237. data/test/test_thread_task.rb +73 -0
  238. data/test/test_transactions.rb +569 -0
  239. data/test/test_transactions_proxy.rb +198 -0
  240. metadata +570 -0
@@ -0,0 +1,86 @@
1
+ {Next tutorial}[link:files/doc/tutorials/02-GoForward_rdoc.html]
2
+ = Getting started
3
+
4
+ == Initializing an empty Roby application
5
+ Go into a shell into the directory you want your application in and run
6
+ $ roby init
7
+ creating tasks/
8
+ creating tasks/.gitattributes
9
+ creating scripts/
10
+ creating scripts/test
11
+ creating scripts/shell
12
+ creating scripts/server
13
+ creating scripts/run
14
+ creating scripts/results
15
+ creating scripts/replay
16
+ creating scripts/generate/
17
+ creating scripts/generate/bookmarks
18
+ creating scripts/distributed
19
+ creating planners/
20
+ creating planners/main.rb
21
+ creating data/
22
+ creating data/.gitattributes
23
+ creating controllers/
24
+ creating controllers/.gitattributes
25
+ creating config/
26
+ creating config/roby.yml
27
+ creating config/init.rb
28
+ creating config/app.yml
29
+ creating Rakefile
30
+ creating README.txt
31
+
32
+
33
+ You can see that the following directories are created:
34
+ tasks:: definition of task models
35
+ planners:: definition of planner models
36
+ controllers:: definition of the robot controllers
37
+ data:: data files
38
+ config:: robots configurations
39
+ test:: the test suites
40
+ log:: the log files (output of the last run)
41
+ results:: sets of logs that have been saved by scripts/results
42
+ scripts:: the standard Roby tools. Call them with --help to know what they are doing
43
+
44
+ The .gitattributes in empty directories is a trick allowing to commit an
45
+ empty Roby application with +git+ using
46
+ git init
47
+ git add .
48
+ git commit
49
+
50
+ Without it, +git+ would ignore those directories.
51
+
52
+ == Overview of Roby applications structure
53
+
54
+ In a single Roby application, someone can define multiple specific
55
+ _controllers_, tailored for specific robots. A specific Roby controller is
56
+ defined by a /robot name/ and a /robot type/. These two parameters define what
57
+ models and what configuration files the system will load on startup. Both
58
+ models and configuration files can be sorted into:
59
+ * a set common to all robots and robot types
60
+ * a set specific to all robots of the same type
61
+ * a set specific to a single robot
62
+
63
+ See Roby::Application for more details on the configuration/models loading logic.
64
+
65
+ == Creating a simple robot
66
+
67
+ During the tutorials, we will be creating different robots which is done by the
68
+ <tt>roby robot</tt> command. For instance, run
69
+ $ roby robot EmptyRobot
70
+ creating planners/EmptyRobot/
71
+ creating planners/EmptyRobot/main.rb
72
+ creating tasks/EmptyRobot/
73
+ creating tasks/EmptyRobot/.gitattributes
74
+ creating controllers/EmptyRobot.rb
75
+ creating config/EmptyRobot.rb
76
+
77
+ This creates the basic templates for the robot named EmptyRobot. The following
78
+ tutorials will explain their role to you.
79
+
80
+ = Next tutorial
81
+
82
+ {The next tutorial}[link:files/doc/tutorials/02-GoForward_rdoc.html] will show you
83
+ the basic plan model used by Roby and some central tool, which allow to execute the
84
+ Roby applications and to interact/control them remotely.
85
+ ---
86
+ vim: tw=80
@@ -0,0 +1,220 @@
1
+ {Previous tutorial}[link:files/doc/tutorials/01-GettingStarted_rdoc.html]
2
+ {Next tutorial}[link:files/doc/tutorials/03-PlannedPath_rdoc.html]
3
+ = The GoForward tutorial: making a simple robot move
4
+ This tutorial will make you create a simulated robot controller which makes the
5
+ robot go forward at constant speed. It will show you what a task is, how to
6
+ start a Roby controller and how to interact with it using the Roby shell.
7
+
8
+ First, we will define a GoForward task model, represented by a subclass
9
+ of Roby::Task. Tasks, which are instances of this model, have two roles:
10
+ * they _represent_ the 'go forward' activity in the plan. i.e. it represents
11
+ its properties, allowing to assess that its execution is going well
12
+ * they actually _make_ the robot 'go forward': they execute the code necessary
13
+ to do it, or activate an external process which will do that.
14
+
15
+ What we will see here is the second point. The first point will be discussed in
16
+ more details in the fourth tutorial: {error handling}[link:files/doc/tutorials/04-ErrorHandling_rdoc.html]
17
+
18
+ = A first attempt
19
+ == Writing the robot task model, and writing the robot controller
20
+ Edit <tt>tasks/go_forward.rb</tt> and add
21
+ class GoForward < Roby::Task
22
+ # The GoForward task needs the robot speed to be specified
23
+ arguments :speed
24
+
25
+ # Block called at every execution loop. It simulates the robot moving at
26
+ # the specified speed.
27
+ poll do
28
+ State.pos.x += speed
29
+ end
30
+
31
+ # No specific action should be taken to make the task stop
32
+ terminates
33
+ end
34
+
35
+ Now, create the robot we will be working on. In the roby application we
36
+ have created in {the first tutorial}[link:files/doc/tutorials/01-GettingStarted_rdoc.html],
37
+ run
38
+ roby robot goForward
39
+
40
+ And in the controller file, <tt>controllers/goForward.rb</tt> do
41
+ # Define the original value of x
42
+ State.pos.x = 0
43
+
44
+ # Will display the value of x every 1 second
45
+ Roby.every(1) do
46
+ puts State.pos.x
47
+ end
48
+
49
+ # Create the task and start moving !
50
+ Roby.plan.insert(go = GoForward.new(:speed => 0.1))
51
+ puts "Going forward at speed #{go.speed}"
52
+ go.start!
53
+
54
+ You can then start the robot controller with <tt>scripts/run</tt> and stop it with CTRL+C.
55
+
56
+ $ scripts/run goForward
57
+ 335705:25:08.324 (goForward) loading controller file /home/doudou/dev/roby-tutorials/controllers/goForward.rb
58
+ Going forward at speed 0.1
59
+ 335705:25:08.356 (goForward) done initialization
60
+ 0
61
+ 0.9
62
+ 1.9
63
+ 2.9
64
+ 335705:25:16.449 (Roby) received interruption request
65
+ 335705:25:16.524 (Roby) control quitting. Waiting for 1 tasks to finish (1 tasks still in plan)
66
+
67
+ == Broken down explanation
68
+ * the line
69
+ State.pos.x = 0
70
+ initializes the robot's state. In general, it is done in the robot's
71
+ configuration file, config/goForward.rb (see below)
72
+ * the line
73
+ arguments :speed
74
+ in the task model tells Roby that the GoForward tasks require a 'speed'
75
+ argument. If it is omitted, the task has no means to actually perform its
76
+ action (it does not know at what speed it is supposed to move), and therefore
77
+ cannot be started. Replace
78
+ Roby.plan.insert(go = GoForward.new(:speed => 0.1))
79
+ by
80
+ Roby.plan.insert(go = GoForward.new)
81
+ and you'll get
82
+
83
+ Roby::EventNotExecutable in GoForward{}:0x4854d110[]/start: start! called on GoForward{}:0x4854d110[] which is partially instanciated
84
+ ./controllers/goForward.rb:15
85
+
86
+ a <i>partially instanciated</i> task being a task whose all required
87
+ arguments are not set.
88
+
89
+ * to understand the meaning of the +poll+ statement, you have to understand
90
+ the idea behind Roby's execution model. Roby relies on a _synchronous_
91
+ execution model, which is basically a two-steps loops (a more detailed
92
+ explanation will come in the following tutorials). This two-steps loops
93
+ is basically:
94
+ 1. gather all events that have occured since the last loop
95
+ 2. react to those events
96
+
97
+ What should be noted here is that the duration of this whole execution loop
98
+ is also a higher bound for the plan-based reaction to new situations. In
99
+ other words, it means that the worst-case latency between the moment
100
+ something happens and the moment the system reacts to it is the duration of
101
+ the execution cycle. In general, one considers that the duration of the
102
+ execution cycle should be small with respect to the system's dynamic (the
103
+ latency in reaction must not have a physical effect).
104
+
105
+ Now, what is the role of +poll+ here ? The block given to +poll+ is executed
106
+ at each execution cycle <i>while the task is running</i>. It can therefore be
107
+ used to break done lengthy computation in small steps, or represent a computation
108
+ thread in the plan, using a task (Roby::PlannerTask does this to represent a plan
109
+ generation thread).
110
+
111
+ * we did not specify a robot name in the call to <tt>scripts/run</tt>. In that
112
+ case, Roby instantiated a robot named 'goForward' of type 'goForward'
113
+ * in general, one does not want the robot to start moving just after
114
+ initialization. To have an interactive interface to the robot's actions, you
115
+ can use the <tt>scripts/shell</tt> tool. See below.
116
+
117
+ = Refining the goForward controller
118
+ == File loading at startup and configuration files
119
+ Roby loads many files at startup, whose exact set of files is determined by the
120
+ robot name and type. The general rule is that the files are loaded from the
121
+ least specific ones (i.e. the files common to all robots) to the most specific ones
122
+ (i.e. the files that are specific to a given robot name).
123
+
124
+ In this tutorial, the <i>task model</i> is global and will be loaded in all
125
+ controllers of this Roby application. The controller file, on the other hand,
126
+ is defined for the goForward robot.
127
+
128
+ What we want here is move the state initialization from the controller file
129
+ into the robot's configuration file. To do that, you just have to move the
130
+ corresponding line into <tt>config/$NAME.rb</tt>, which is in our case
131
+ <tt>config/goForward.rb</tt>, so that this latter file looks like
132
+
133
+ Roby::State.update do |s|
134
+ # define the original value of x
135
+ s.pox.x = 0
136
+ end
137
+
138
+ and test that everything still works !.
139
+
140
+ See Roby::Application for an explanation of how files are organized in a Roby
141
+ application.
142
+
143
+ == Interacting with the Roby controller
144
+ First, we usually don't want to hardcode the robot actions in its controller.
145
+ Instead, it is better to be able to <em>send a command</em> to the robot. Do
146
+ do that, we must first define an <em>action</em> in the robot's main planner.
147
+ Edit <tt>planners/goForward/main.rb</tt> and add the following code to the
148
+ definition of the MainPlanner class.
149
+
150
+ method(:move) do
151
+ GoForward.new :speed => arguments[:speed]
152
+ end
153
+
154
+ and remove the last three lines of controllers/goForward.rb. You can now start
155
+ the application and wait for the "done initialization" line.
156
+
157
+ $ scripts/run goForward
158
+ 335814:29:25.107 (goForward) loading controller file /home/doudou/dev/roby-tutorials/controllers/goForward.rb
159
+ 335814:29:25.108 (goForward) done initialization
160
+ 0
161
+ 0
162
+
163
+ Now, start a shell and wait its prompt.
164
+
165
+ $ scripts/shell
166
+ >>
167
+
168
+ Let's now check that the <tt>move</tt> action does exist
169
+ >> actions
170
+ => [move]
171
+
172
+ ... and start the move
173
+ >> m = move! :speed => 0.2
174
+ => GoForward{speed => 0.2}:0x4886b248[]
175
+
176
+ >> m.running?
177
+ => true
178
+ >> running_tasks
179
+ =>
180
+
181
+ Task Since State
182
+ GoForward{speed => 0.2}:0x4886b248[] Wed Apr 23 08:31:29 +0200 2008 running
183
+
184
+
185
+ Now, to stop it ...
186
+ >> m.stop!
187
+ => []
188
+ task GoForward{speed => 0.2}:0x4886b248[] stopped by user request
189
+ >> m.running?
190
+ => false
191
+ >> m.finished?
192
+ => true
193
+ >> m.success?
194
+ => false
195
+ >> m.failed?
196
+ => true
197
+
198
+ The task has been interrupted. From the system point of view, it means that it
199
+ has not finished successfully, hence <tt>m.success?</tt> and <tt>m.failed?</tt>
200
+ return respectively false and true.
201
+
202
+ Now, to make the whole Roby controller quit:
203
+ >> quit
204
+ =>
205
+
206
+ Note that you don't have to restart the shell between to runs: if you start the
207
+ controller again, the same shell will reconnect automatically to the new
208
+ controller.
209
+
210
+ = Next tutorial
211
+
212
+ This tutorial showed you how to build a very simple task model, and how to
213
+ create planner methods to interface with the shell. The {next
214
+ tutorial}[link:files/doc/tutorials/03-PlannedPath_rdoc.html] will build upon
215
+ that by making you create a very small plan, in which different tasks represent
216
+ different aspects of the robot activity. The fourth tutorial will then be about
217
+ displaying the execution trace of that plan to understand what happens under the
218
+ hood.
219
+ ---
220
+ vim: tw=80 et
@@ -0,0 +1,268 @@
1
+ {Previous tutorial}[link:files/doc/tutorials/02-GoForward_rdoc.html]
2
+ {Next tutorial}[link:files/doc/tutorials/04-EventPropagation_rdoc.html]
3
+ = Planning and following a path
4
+ We'll now use a (slightly) more complex system to make our robot move. The
5
+ robot will now have a goal, defined as a (x, y) point. It will generate a
6
+ trajectory which leads it to that goal, and then execute that trajectory.
7
+
8
+ This tutorial therefore shows the following:
9
+ * how multiple activities can be _temporally_ coordinated to make the robot
10
+ reach a defined goal, and
11
+ * how the plan represents how one activity relates to another.
12
+
13
+ In this new robot, three activities will be used to make the robot reach
14
+ its goal. The plan will therefore represent various things:
15
+ * the three activities: the high-level activity which represent the goal of
16
+ the robot; the path planning activity and the path execution activity.
17
+ * how these activities relate to each other. For that, Roby defines <it>
18
+ task relations</it>.
19
+ * how the plan describes the temporal relations between these activities (i.e.
20
+ when a given activity should be started).
21
+
22
+ To hold all these, we will create a new robot:
23
+
24
+ roby robot PathPlan
25
+
26
+ == Defining the task models
27
+ This section will describe the task models, without the actual implementation
28
+ of the actual implementation of these activities. That implementation is
29
+ discussed later in that tutorial. The goal is to first make you grasp what the
30
+ task models, and the plan model is about and only then how the tasks can
31
+ actually control the robot itself.
32
+
33
+ * the +MoveTo+ task express the current goal of the robot, and holds the path
34
+ data. Open <tt>tasks/move_to.rb</tt> and add the following:
35
+ class MoveTo < Roby::Task
36
+ terminates
37
+
38
+ # The movement goal
39
+ argument :goal
40
+ # The generated path
41
+ def path; data end
42
+ end
43
+
44
+ * the +ComputePath+ task generates the path on behalf of a +MoveTo+. When
45
+ successful, it updates the +data+ attribute of the +MoveTo+ task it is
46
+ planning. It uses a standard task, Roby::ThreadTask, which allows to
47
+ represent the execution of a separate thread into the main plan. Open
48
+ <tt>tasks/compute_path.rb</tt> and add the following:
49
+
50
+ require 'roby/thread_task'
51
+ class ComputePath < Roby::ThreadTask
52
+ # The movement goal
53
+ argument :goal
54
+ # The maximum speed limit
55
+ argument :max_speed
56
+ end
57
+
58
+ * finally, +TrackPath+ takes the path generated and follows it. Open
59
+ <tt>tasks/track_path.rb</tt> and add the following:
60
+ class TrackPath < Roby::Task
61
+ terminates
62
+
63
+ # The task holding the path data
64
+ argument :path_task
65
+ end
66
+
67
+ *Note*: the file names are "best practice" recommandations. They are not at all
68
+ required for the application to work.
69
+
70
+ == Building the movement plan
71
+ Let's add a +move_to+ action to our robot, which builds the plan corresponding
72
+ to the whole movement. The action definition, in
73
+ <tt>planners/PathPlan/main.rb</tt> would look like this:
74
+
75
+ # Note: the method arguments are accessed through the +arguments+ hash
76
+ method(:move_to) do
77
+ # The goal point
78
+ goal = Pos::Vector3D.new(*arguments.values_at(:x, :y))
79
+ # The high-level representation of the movement
80
+ move = MoveTo.new :goal => goal
81
+ move.realized_by compute = ComputePath.new(:goal => goal, :max_speed => 1.0)
82
+ move.realized_by track = TrackPath.new(:path_task => move)
83
+
84
+ move.on :start, compute, :start
85
+ compute.on :success, track, :start
86
+ track.forward :success, move, :success
87
+
88
+ move
89
+ end
90
+
91
+ The first part creates the <em>task structure</em>, which expresses the
92
+ relationships of the different tasks of the plan. This simple plan uses only
93
+ one kind of relation, the RealizedBy relation. In this relation, the child task
94
+ (i.e. +compute+ and +track+) are simple activities which achieve the parent's higher-level
95
+ action.
96
+
97
+ The second part creates the <em>event structure</em>, which expresses how the
98
+ plan should respond to new situations. In our case, the three line describe the following:
99
+ * the path planning must be started when the movement is started. This uses the Signal
100
+ event relation.
101
+ * the path execution must be started when the path planning has successfully finished, and
102
+ * the movement <it>has finished</it> when the path tracking <it>has finished</it>. This uses
103
+ the Forward relation.
104
+
105
+ The difference between those two relations is subtle, so let's try to explain a bit more:
106
+ * in the first two cases, what the system must do is <it>executing a new action</it> in
107
+ response to a new situation. When the +start+ event of +move+ is emitted, the +move+
108
+ activity has just started (i.e. all necessary actions have been taken to start that
109
+ new activity). The system should then make what is necessary to start computing the
110
+ path: it calls the _command_ of the +start+ event of +compute+.
111
+ * in the third case, however, no specific action should be taken to end the
112
+ +move+ task. Instead, the plan expresses that the +move+ task is finished
113
+ <it>as soon as</it> the +track+ task is. Another way to put it is that the
114
+ situation represented by the +success+ event of MoveTo is, in this particular
115
+ plan, the same than the situation represented by the +success+ event of
116
+ TrackPath. More generally, if +a+ is forwarded to +b+ all situations that lead
117
+ to the emission of +a+ also lead to the emission of +b+. Or, in other words, that
118
+ the situation represented by +b+ is a superset of the one represented by +a+
119
+ (the equality, like here, is a particular case)
120
+
121
+ link:../../images/event_generalization.png
122
+
123
+ *Example*: in this plan, the +success+ event of a particular low-level action
124
+ is forwarded in more high-level parts of the plan. This allows to actually
125
+ link the low and high level parts of the plan and reason on that link.
126
+
127
+ Task relations allow the system to keep track of what a given task is useful for,
128
+ what are error conditions and how to react to errors. The next two tutorials will
129
+ describe these parts in more details.
130
+
131
+ == Running this unfinished controller
132
+
133
+ Let's run this controller. Launch the controller
134
+ $ scripts/run PathPlan
135
+
136
+ In another terminal, launch the shell and start the move_to! action
137
+ $ scripts/shell
138
+ >> move_to! :x => 10, :y => 10
139
+ => MoveTo{goal => Vector3D(x=10.000000,y=10.000000,z=0.000000)}:0x48350370[]
140
+ >>
141
+ !Roby::ChildFailedError
142
+ !at [336040:01:45.419/186] in the failed event of ComputePath:0x483502e0
143
+ !block not supplied (ArgumentError)
144
+ ! /home/doudou/dev/roby/lib/roby/thread_task.rb:51:in `instance_eval',
145
+ ! /home/doudou/dev/roby/lib/roby/thread_task.rb:61:in `value',
146
+ ! /home/doudou/dev/roby/lib/roby/thread_task.rb:61:in the polling handler,
147
+ ! /home/doudou/system/powerpc-linux/ruby-1.8.6/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require',
148
+ ! /home/doudou/system/powerpc-linux/ruby-1.8.6/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require',
149
+ ! scripts/run:3
150
+ !
151
+ !The failed relation is
152
+ ! MoveTo:0x48350370
153
+ ! owners: Roby::Distributed
154
+ ! arguments: {:goal=>Vector3D(x=10.000000,y=10.000000,z=0.000000)}
155
+ ! realized_by ComputePath:0x483502e0
156
+ ! owners: Roby::Distributed
157
+ ! arguments: {:max_speed=>1.0,
158
+ ! :goal=>Vector3D(x=10.000000,y=10.000000,z=0.000000)}
159
+ !The following tasks have been killed:
160
+ ! ComputePath:0x483502e0
161
+ ! MoveTo:0x48350370
162
+
163
+ Mmmm... What happened ? The call to <tt>move_to!</tt> returned properly, which
164
+ means that the plan has been properly generated and the MoveTo high-level
165
+ action started. Nonetheless, an error occured.
166
+
167
+ The error message appeared because an ArgumentError exception has been raised
168
+ in <tt>thread_task.rb:51</tt> Looking at the documentation of Roby::ThreadTask,
169
+ we see that the definition of ComputePath has not called the Roby::ThreadTask.implementation
170
+ statement, and as such the polling handler failed. Roby answers to that by
171
+ emitting the +failed+ event of the problematic task.
172
+
173
+ The plan-related error (ChildFailedError) has then been generated by Roby's
174
+ plan analysis:
175
+ * a +realized_by+ relation between MoveTo and ComputePath exists, which means
176
+ that MoveTo cannot be achieved without executing ComputePath first.
177
+ * ComputePath failed, so <i>in the current state of the plan</i>, the MoveTo
178
+ action cannot be achieved either.
179
+
180
+ A more complete description of errors and, more importantly, of how to handle
181
+ them is given in the following tutorials.
182
+
183
+ == Implementation of +ComputePath+ and +TrackPath+
184
+ The first section did mainly explain how the plan represents the logical
185
+ relations between each tasks and each task's events. We will now get into the
186
+ details of actually implementing these tasks.
187
+
188
+ * First, we have to initialize the position in <tt>tasks/PathPlan.rb</tt>
189
+
190
+ Roby::State.update do |s|
191
+ s.pos = Roby::Pos::Vector3D.new
192
+ end
193
+
194
+ * for +ComputePath+, we will simply generate a random set of points in-between
195
+ the current robot position and the specified goal. In general (i.e. not here,
196
+ but in a real case), this process takes time and as such cannot be done in
197
+ one pass of the execution cycle. We will therefore use a thread to do it,
198
+ leaving the actual thread management to Roby::ThreadTask:
199
+
200
+ # The robot position at which we should start planning
201
+ # the path
202
+ attr_reader :start_point
203
+
204
+ # Initialize start_point and call ThreadTask's start command
205
+ event :start do |context|
206
+ @start_point = State.pos.dup
207
+ super
208
+ end
209
+
210
+ # Implementation of the computation thread
211
+ implementation do
212
+ path = [start_point]
213
+ while goal.distance(path.last) > max_speed
214
+ u = goal - path.last
215
+ u /= u.length / max_speed
216
+ path << path.last + u
217
+ end
218
+ path << goal
219
+
220
+ Robot.info "#{path.size} points between #{start_point} and #{goal}"
221
+ path
222
+ end
223
+
224
+ on :success do |ev|
225
+ # Parents is a ValuSet, it has no #first method. Get
226
+ # the first element with #find
227
+ parents.find { true }.data = result
228
+ end
229
+
230
+ See Roby::ThreadTask to implement _interruptible_ external threads.
231
+
232
+ Robot is a namespace which (among other things) can be used to access an
233
+ application-specific logger set up by Roby itself. It answers to #debug,
234
+ #info, #warning and #fatal, and by default is at the INFO level. The Logger
235
+ object itself is accessible at Robot.logger. Therefore, use
236
+ Robot.logger.level= to change the logger level itself.
237
+
238
+ * as stated before, MoveTo does not require any special code. It is here
239
+ only to represent a high level activity (the whole movement), not to actually
240
+ execute it.
241
+
242
+ * TrackPath will then take the path data and execute the corresponding movement. For
243
+ the purpose of this tutorial, it will simply move to the next point in the path
244
+ at each execution cycle:
245
+
246
+ # The current waypoint
247
+ def current_waypoint; path_task.data[@waypoint_index] end
248
+
249
+ poll do
250
+ @waypoint_index ||= 0
251
+ State.pos = current_waypoint
252
+ @waypoint_index += 1
253
+ if @waypoint_index == path_task.data.size
254
+ emit :success
255
+ end
256
+
257
+ Robot.info "moved to #{current_waypoint}"
258
+ end
259
+
260
+ = Next tutorial
261
+
262
+ The {next tutorial}[link:files/doc/tutorials/04-EventPropagation_rdoc.html] will
263
+ allow you to understand more by actually seeing what happens during the plan
264
+ execution. After this tutorial, you should be able to build simple task
265
+ models and simple plans, as well as execute them and understand the most common
266
+ error -- ChildFailedError.
267
+ ---
268
+ vim: tw=80 et