Project

General

Profile

Genom3tutorialdemo-genom3 » History » Version 22

Anthony Mallet, 2019-07-16 17:34
Fix broken link

1 20 Aurélie Clodic
h1. Genom3 through an example
2 1 Aurélie Clodic
3
{{toc}}
4
5
6 6 Aurélie Clodic
This section will illustrate genom3 concepts through a concrete example. 
7
8 19 Aurélie Clodic
The demo compoment controls a virtual mobile that can move in a 1D world. Some of the services the module offers are:
9 1 Aurélie Clodic
* read and set the current speed at any moment
10
* move the mobile to a given position
11
* move the mobile of a given distance (from its current position)
12
* monitor when the mobile passes a given position
13
* stop the motion 
14
15 19 Aurélie Clodic
Moreover, the demo component exports a port with the current state of the mobile (position and speed).
16 1 Aurélie Clodic
17 7 Aurélie Clodic
18
h3. The component description file: .gen file
19
20 22 Anthony Mallet
https://git.openrobots.org/projects/demo/repository/demo-genom3/revisions/master/entry/demo.gen
21 19 Aurélie Clodic
22 6 Aurélie Clodic
We will describe the .gen description file. It is made up of several parts, each of them being identified with a keyword
23 1 Aurélie Clodic
* @component@
24
* @ids@
25
* @port@
26
* @exception@
27
* @task@
28
* @attribute@
29
* @function@
30
* @activity@
31
32 5 Aurélie Clodic
This .gen reflects the fact that a component need to define an interface made of a set of services and data ports. A component must provide a service invocation facility as well as unidirectional (input and output) data ports. It must be able to send and receive events. It has to define an internal data structure, named the @ids@, that is used by codels to store global and permanent objects.
33
Each codel has access to the @ids@ objects and use them to communicate with other codels within the component.
34
Finally, a component has to define one or more @execution tasks@ that represent the execution context (e.g. thread) in which services are run. Those tasks may be periodic or aperiodic.
35 1 Aurélie Clodic
36 11 Aurélie Clodic
!blockdiagram.jpg!
37 10 Aurélie Clodic
38 8 Aurélie Clodic
The easiest way is to see how all of this is defined is to start from an existing file, so you can download ".gen" file and ".idl" file. We will now explain step by step each part of these files.
39 5 Aurélie Clodic
40 7 Aurélie Clodic
h4. Data structure definition 
41 5 Aurélie Clodic
42 7 Aurélie Clodic
A component description always start with the definition of the data types used in the interface. Types are typically defined in separate files and @#included@ in the description, so that the definitions can be shared amongst other components. The syntax used is the subset of the IDL language (part of the OMG CORBA [5] specication) related to data type definitions. Using IDL guarantees the programming language independance and offers a standardized approach. Although IDL is part of CORBA, it should be clear that components are not tied anyhow to CORBA.
43
44
<pre>
45
#include "demoStruct.idl"
46
</pre>
47
48
The #include "demoStruct.idl" statement works as a header file in C and includes idl data structure. This file contains all the necessary declarations for the definition of the internal database. These structures are then used in the .gen file. In this example, the file "demoStruct.idl" contains the definition of the position and the speed. This file is preferably located in the same directory as .gen file, since it contributes to the definition of the component interface. 
49
50
<pre>
51
#ifndef IDL_DEMO_STRUCT
52
#define IDL_DEMO_STRUCT
53
54
module demo {
55
56
  const unsigned long task_period = 400;
57
  const double millisecond = 0.001;
58
59
  struct state {
60
    double position;  /* current position (m) */
61
    double speed;     /* current speed (m/s) */
62
  };
63
64
  enum speed {
65
    SLOW,
66
    FAST
67
  };
68
};
69
#endif 
70
</pre>
71
72
73 1 Aurélie Clodic
h4. @component@
74 5 Aurélie Clodic
75 1 Aurélie Clodic
The component declaration describes the instance of the GenoM3 component. It is defined by a unique name (an identifier) that also defines an IDL scope for any embedded types. See the "component declaration documentation":http://homepages.laas.fr/mallet/share/doc/genom3/genom3.html/Component-declaration.html#Component-declaration for details.
76
77
<pre>
78
component demo {
79
  version	"1.1";
80
  email		"openrobots@laas.fr";
81
  lang		"c";
82
  require	"genom3 >= 2.99.20";
83
</pre>
84
85
86
* version : The component version number, as a string
87
* lang : The programming language of the codels interface
88 5 Aurélie Clodic
* email : A string containing the e-mail address of the author of the component.
89 1 Aurélie Clodic
* requires : A list of dependencies of the component. It indicates an external dependency on a software package that is required. It assumes that the package is using the pkg-config utility. Each string should contain a package name in pkg-config format. 
90
91
NB: component declaration is not over, the final } is left for the end @.gen@ file.
92
93
h4. @ids@
94 5 Aurélie Clodic
95
@ids@ stands for internal data structure, it is used by codels to store global and permanent objects.
96
Each codel has access to the @ids@ objects and use them to communicate with other codels within the component.
97
98 1 Aurélie Clodic
For our example, we considerto store the state, the speed reference and the position of the mobile: 
99
<pre>
100
ids {
101
  demo::state state;          /* Current state */
102
  demo::speed speedRef;       /* Speed reference */
103
  double      posRef;
104
};
105
</pre>
106
107 7 Aurélie Clodic
@demo::state@ and @demo::speed@ are types defined in the demoStruct.idl file (see above).
108 5 Aurélie Clodic
109 1 Aurélie Clodic
h4. @port@
110
111 5 Aurélie Clodic
A component define input and output data ports, used to implement data flow connections in parallel to services.
112
Ports implement the data flow between components as a publish/subscribe model. Ports have a name and a type and can be either out (for publishing data) or in (for subscribing to a sibling out port). Data ports Data ports are defined via the in or out keyword, followed by an IDL type and the name of the port e.g.: 
113 4 Aurélie Clodic
<pre>
114
port in data<type> name;
115 1 Aurélie Clodic
port out data<type> name;
116 4 Aurélie Clodic
</pre>
117
118
In our example, we choose to export the state of the mobile to let this information accessible for example to another port from another component:
119 5 Aurélie Clodic
<pre>
120 1 Aurélie Clodic
/* ---- Port declaration ---- */
121
  port out demo::state Mobile;
122
</pre>
123
124
h4. @exception@
125 6 Aurélie Clodic
126 19 Aurélie Clodic
It is possible to define exception.
127 1 Aurélie Clodic
<pre>
128
/* ---- exception declaration ---- */
129
  exception TOO_FAR_AWAY {double overshoot;};
130
  exception INVALID_SPEED;
131
</pre>
132
133
h4. @execution task@
134
135 6 Aurélie Clodic
Tasks define an execution context suitable for running activities. A task may define a state machine and associated codels. 
136
The state machine starts in the start state when the task is created during component initialization. 
137
Task description follows this scheme:
138
<pre>
139
task name {
140 14 Aurélie Clodic
period 100ms;
141
priority 200;
142
stack 20k;
143
codel start tstart(in ::ids) yield main;
144
codel main tmain(in d, out s) yield main, stop;
145
codel stop tstop() yield ether;
146 6 Aurélie Clodic
};
147
</pre>
148 1 Aurélie Clodic
149
Tasks can define the following properties:
150
* @period@ The granularity of the codel scheduler. Periodic task will sequence the codels they manage at that frequency.
151
* @delay@ The delay from the beginning of each period after which codels are run. This can be used to delay two tasks running at the same period in the same component.
152
* @priority@ Can be used to prioritize different tasks whithin the same component.
153
* @scheduling real-time@ This indicates that the task requires real-time scheduling. This may not be supported by all templates.
154
* @stack@ Defines the required stack size for this task. The stack size should be big enough to run all codels that the task manages.
155
156
157 7 Aurélie Clodic
In our example, we choose to get the task_period from the idl file i.e. @demo::task_period@ parameter:
158 1 Aurélie Clodic
<pre>
159
/* ---- Execution task declaration ---- */
160
161
  task motion {
162
    period	demo::task_period ms;
163
    priority	100;
164
    stack	4000;
165
    codel <start>	InitDemoSDI(out ::ids, port out Mobile) yield ether;
166 2 Aurélie Clodic
  };
167
</pre>
168 6 Aurélie Clodic
169 12 Aurélie Clodic
h4. services declarations
170 6 Aurélie Clodic
171 2 Aurélie Clodic
A service is an interface for running codels. It can be invoked via a request on the component service port. A service has optional input and output data and a list of failure reports. Input data is stored in the IDS (and output read from there), so that codels can access it. A service might be incompatible with other services of the same component or can be started multiple time, provided it is compatible with itself. It always interrupts other incompatible services when starting. A service invocation triggers an activity that manages codel execution. An activity is described by a Petri net in which places correspond to codels execution and transitions are events generated either externally or implicitely by the return value of codels.
172
173
Service description follows this scheme:
174
<pre>
175
service name(inout s) {
176
doc "Service description";
177
task taskname;
178
validate svalidate();
179
throws ERROR_1, ERROR_2, ...;
180
interrupts name;
181
codel <start> sstart() yield step1;
182
codel <step1> sstep1() yield step1, step2;
183
codel <step2> sstep2() yield ether;
184
codel <stop> sstop() yield ether;
185
};
186
</pre>
187
where:
188
* @name@ corresponds to the name of the service
189
* @s@ corresponds to the parameter of the service. Parameter could be in/inout/out depending of its type. It is possible to have several parameters.
190
* @task@ corresponds to the task that handle the service
191
* @validate@ corresponds to a function that would be called once at the beginning of the service execution and that aims to check service parameter(s) consistency
192
* @throws@ corresponds to the list of failure report(s)
193
* @interrupts@ corresponds to the service(s) that would be automatically interrupted when the this service is called
194 1 Aurélie Clodic
195 2 Aurélie Clodic
When an activity starts, the start event is generated and the corresponding codel executed. Similarly, the activity is interrupted whenever the stop event is generated.
196 1 Aurélie Clodic
Asynchronous events trigger the execution of the corresponding codel (if any). A special sleep transition is defined so that an activity can be put in a sleeping state, waiting for external events or a stop to trigger a new transition. The activity stops when all active places in the Petri net have returned the special ether event. If the execution task of a service is periodic, transitions are executed at each period. They are otherwise executed as soon as all the codels corresponding to active places have returned. The codel execution order is undefined.
197 12 Aurélie Clodic
198
!activitydiagram.jpg!
199 2 Aurélie Clodic
200 7 Aurélie Clodic
It should be noticed that no direct remote procedure call (RPC) for service invocation between components is allowed. RPC should be performed by external applications that take care of setting up the architecture of components. While this differs from traditional approaches, this guarantees that components can be controlled and will not interfere with the system. This also grants an increased reusability since no component explicitely depends on a particular set of services implemented by other components.
201 3 Aurélie Clodic
202 1 Aurélie Clodic
3 types of services are available through GenoM3: attribute, function and activity. Each follow the same service pattern.
203 2 Aurélie Clodic
204 1 Aurélie Clodic
205
h5. @attribute@
206 3 Aurélie Clodic
207 7 Aurélie Clodic
@attribute@ service type should be used...
208 3 Aurélie Clodic
209 1 Aurélie Clodic
<pre>
210
 attribute SetSpeed(in speedRef = demo::SLOW	:"Mobile speed")
211
  {
212
    doc		"To change speed";
213
    validate	controlSpeed (local in speedRef);
214
    throw	INVALID_SPEED;
215
  };
216
217
  attribute GetSpeed(out speedRef =	:"Mobile speed")
218
  {
219
    doc		"To get current speed value";
220
  };
221
</pre>
222
223
h5. @function@
224 7 Aurélie Clodic
225 1 Aurélie Clodic
<pre>
226
 function Stop()
227
  {
228
    doc		"Stops motion and interrupts all motion requests";
229
    interrupts	MoveDistance, GotoPosition;
230
  };
231
</pre>
232
233
h5. @activity@
234 7 Aurélie Clodic
235 1 Aurélie Clodic
<pre>
236
activity MoveDistance(in double distRef = 0	:"Distance in m")
237
  {
238
    doc		"Move of the given distance";
239
    validate	controlDistance(in distRef, in state.position);
240
241
    codel <start>	mdStartEngine(in distRef, in state.position,
242
                              out posRef) yield exec, ether;
243
    codel <exec>	mdGotoPosition(in speedRef, in posRef, inout state,
244
                               port out Mobile) yield exec, end;
245
    codel <end, stop>	mdStopEngine() yield ether;
246
    interrupts	MoveDistance, GotoPosition;
247
    task	motion;
248
    throw	TOO_FAR_AWAY;
249
  };
250
</pre>
251 8 Aurélie Clodic
252 13 Aurélie Clodic
h4. Data flow
253
254
!dataflow.jpg!
255 8 Aurélie Clodic
256
h3. Module generation
257
258
You can copy demo.gen and demoStruct.idl in your demo-genom3 repository.
259
260
<pre>
261
genom3 skeleton demo.gen
262
</pre>
263
264
From now on, the component is ready to be compiled and run. You can have a look at the result of the command. GenoM3 created two new directories (@codels/@ and @autoconf/@) and several new files.
265 9 Aurélie Clodic
* Algorithms (or a part of them) are grouped in the directory @codels/@. The files in that directory give you template to start from, and also let GenoM3 produce a module even if you still do not have written a single line of code.
266
* The @Makefile.am@ and @configure.ac@ files are also under your control. These are the main files which are used for the compilation of the module. 
267 1 Aurélie Clodic
268 9 Aurélie Clodic
h3. Codels writing
269
270
In the codels directory, you would find these two files: @demo_codels.c@ and @demo_motion_codels.c@.
271
272
h4. @demo_codels.c@
273 15 Aurélie Clodic
274
http://git.laas.fr/git/demo-genom/tree/codels/demo_codels.c?h=genom3
275
276
In this file, we will found codels executed by the control task such as the validation codels , e.g. controlSpeed (Validation codel of attribute SetSpeed), controlPosition (Validation codel of activity GotoPosition) and controlDistance (Validation codel of activity MoveDistance).. 
277
278
279
h4. @demo_motion_codels.c@
280
281
http://git.laas.fr/git/demo-genom/tree/codels/demo_motion_codels.c?h=genom3
282
283
In this file, we will found functions attached to the motion task, such as :
284
* <start> codel of the task
285
* <start> and <exec> codel of the GotoPosition activity 
286
* etc
287
288
h3. Module compilation
289
290
We are now ready to compile the module. Note that you could have done it with the empty codels just after generating the skeleton. The result would have been a valid GenoM3 module, runnable, but not doing anyhing of course.
291
292
 # bootstrap the autotools build system
293
<pre>
294
% autoreconf -vi
295
% mkdir build && cd build
296
</pre>
297
 # configure the codels with a set of templates, e.g. for pocolibs :
298
<pre>
299
% ../configure --prefix=$INSTALL_DIR --with-templates=pocolibs/server,pocolibs/client/c
300
</pre>
301
or for ros :
302
<pre>
303 21 Matthieu Herrb
% ../configure --prefix=$INSTALL_DIR --with-templates=ros/server,ros/client/c,ros/client/ros
304 15 Aurélie Clodic
</pre>
305
 # build your module
306
<pre>
307
% make
308
</pre>
309
310
Iterate until there are no more errors. Then, you can install your module:
311
<pre>
312
% make install
313
</pre>
314
315
h3. Module execution
316
317
Given the template choosen the way you will run your module may be different. 
318
319
320
h4. Pocolibs
321
322 16 Aurélie Clodic
h5. Setup (bash version)
323 15 Aurélie Clodic
324 16 Aurélie Clodic
<pre>
325
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$INSTALL_PATH/lib/pkgconfig
326
</pre>
327 15 Aurélie Clodic
328 16 Aurélie Clodic
h5. Launch
329 17 Aurélie Clodic
330
First you need to launch pocolibs:
331 1 Aurélie Clodic
<pre>
332 17 Aurélie Clodic
% h2 init
333 1 Aurélie Clodic
</pre>
334 17 Aurélie Clodic
your module:
335
<pre>
336
% demo -b
337
</pre>
338
and genomix:
339
<pre>
340
% genomixd &
341
</pre>
342
343
Finalement, thanks to eltclsh you will be able to access to your module:
344
<pre>
345
% eltclsh
346
eltclsh > package require genomix
347
eltclsh > genomix::connect 
348
genomix1
349
eltclsh > genomix1  load demo
350
eltclsh > ::demo::GetSpeed 
351
speedRef ::demo::SLOW
352
</pre>
353
354 1 Aurélie Clodic
Note that the use of the tab completion will help you to have access to your module available services. 
355
Moreover, if you do not know which parameter your module needs, you can call the service and then use tab to have access to the parameters.
356 17 Aurélie Clodic
357 1 Aurélie Clodic
Use "-ack" if you want to launch a request in background (useful if you do not want to loose access to the shell):
358 17 Aurélie Clodic
<pre>
359
eltclsh > ::demo::GetSpeed -ack
360
</pre>
361
 
362
363
h4. ROS
364
365 15 Aurélie Clodic
h5. Setup (bash version)
366 19 Aurélie Clodic
367
With $ROS_VERSION, your ros version :
368 16 Aurélie Clodic
<pre>
369 19 Aurélie Clodic
source /opt/ros/$ROS_VERSION/setup.bash
370 16 Aurélie Clodic
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$INSTALL_PATH/lib/pkgconfig
371 18 Aurélie Clodic
export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$INSTALL_PATH/src/ros-nodes:$INSTALL_PATH/share
372 16 Aurélie Clodic
export PYTHONPATH=/opt/ros/groovy/lib/python2.7/dist-packages:$INSTALL_PATH/lib/python2.7/site-packages
373
</pre>
374
375
h5. Launch
376
First you need to launch ros master:
377
<pre>
378
% roscore 
379
</pre>
380
Once it is initialized you can run your module:
381
<pre>
382
% demo-ros -b
383
</pre>
384
385
Then you will be able to use all ros facilities to access to your module, e.g.:
386
<pre>
387
% rosnode info demo
388
</pre>
389
will give you access to all availables services and topics.
390
391
To access to a topic, e.g. /demo/Mobile:
392
<pre>
393
% rostopic echo /demo/Mobile
394
</pre>
395
396
To call a service, e.g. /demo/SetSpeed:
397
<pre>
398
% rosservice call /demo/SetSpeed '{speedRef: {value: 1}}'
399
</pre>