summaryrefslogtreecommitdiff
path: root/doc/objects.rst
blob: b1977974f27eaa4b62aed92063c1092fecfbb639 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
==========================
Tangible Bit Object System
==========================

The Tangible Bit Object System (TBOS) describes physical objects. It
contains including detailed and automatically processable on how they can
be build, how they can be used, and what they can be used for. The TBOS
takes care of the entire life cycle of an object, including information on
maintenance, part replacement, and repair, and disassembly.

Each object has *properties* that describe the object. Each object is
associated with *processes* that describe how the object can be build,
used, maintained, repaired, modified, or dismantled.

Object Descriptions
~~~~~~~~~~~~~~~~~~~

The most important property of each object are its *categories* (types).
This allows placing all objects in a type hierarchy. Each category extends
another category, the most general object category is *Object*; each object
is an instance of one or several category (we allow multiple inheritance
here). The hierarchy of object categories, as known to Tangible Bit, is
stored in ``doc/object_categories.txt`` (TODO should be formalized and
moved outside the ``doc`` directory; it should be possible to just refer to
categories by ID to remove the dependency on a single authority). The
object category also specified which other properties the object has.

The properties of the *Object* category, which are shared by all objects,
are as follows:

.. include:: ../data/types/object.tt
   :literal:

TODO include parsed and beautified version of files instead.

Samples of additional properties that could be defined for a VisualDisplay:

- resolutionX (int)
- resolutionY (int)
- displayWidth (length)
- displayHeight (length)

New object categories can be declared by defining a name and an ID for the
category and by specifying the ID of a parent category (*Object* or a
category derived from it) and a list of additional properties supported by
the new category. Category declarations are given in the Type Declaration
Language, cf. ``formats``.

The following basic types can be used for additional properties:

.. include:: ../data/types/basetypes.tt
   :literal:

All properties that require a unit come with a "natural unit" taken, when
possible, from the `International System of Units
<http://en.wikipedia.org/wiki/International_System_of_Units>`_ (meter,
kilogram, second, ampere, degree Celsius, candela, joule, watt, volt,
hertz, ohm, lumen etc.). Thus units need never be stored in the DB. The
obvious exception is money, where a unit (e.g. USD or EUR) must be
supplied.

Additional properties can also be *complex types*, made up of several
atomic or complex types. Examples of complex types are the *file* and
*process* properties of the *Object* type. Complex types are declared in
the same way as object categories (cf. ``formats``).

Process Descriptions
~~~~~~~~~~~~~~~~~~~~

Processes describe the life cycle of an object: how it and be built; how it
can be used and what it can be used for; how it can be maintained,
repaired, and modified; and how it can be dismantled and discarded or
recycled when it has reached the end of its life cycle. Without processes,
any object would be pretty useless.

Each process description has the following elements:

Metadata
++++++++

.. include:: ../data/types/process.tt
   :literal:

Input
+++++

Lists materials and components that are required for the process; including
the amount or the number of instances required. Materials and objects
listed here are used up or transformed during the process.

Input requirements are probably listed using the TB query language, which
might look like this::

  object ? (category ~ SheetMetal & material = Aluminum & width = 1.5 &
            depth = 0.3 height = 0.003 & copies = 12);
  material ? (category ~ ABS & amount = 0.5);

(12 sheets made from aluminum or steel, size 150x30 cm, height between 3
and 4 mm; and 0.5 kg of ABS plastic.)

A name can be declared before the "?", e.g. ``material "MyMaterial" ?``.
The name used for referring to the object/material later in scripting,
otherwise the category (e.g. "SheetMetal" or "ABS") is used.

The `Booleano <http://code.gustavonarea.net/booleano/>`_\ -based query
syntax is straightforward:

* Logical operators:

  * and: &
  * or: |
  * not: !

* Comparison operators:

  * Equal: = (or maybe ==)
  * Not equal: !=
  * Less/greater [or equal] than: < > <= >=
  * "Similarity": ~ . ``A ~ B`` means:

    * A is a subcategory of B, if A and B are categories
    * A contains B as a substring (case-insensitive), if A and B are
      strings (similar to SQL LIKE)
    * Maybe: abs(A-B) < 0.01, if A and B are numbers (rough equality
      check)
    * Undefined (error) otherwise

* Items are separated using ``;`` or ``&``, indicating that both are
  required; or using ``|`` indicating that one of the is required.

Additional properties, not defined by the object category:

* copies (int): the number of instances required, for discrete items.
  Default is 1.
* amount (mass): the amount (in kilogram) required, for non-discrete items.
  No default value. Only one of *copies* or *amount* may be specified, but
  not both.

The input requirements are often called "bill of materials (BOM)", but they
can contain materials *and* objects.

Tools
+++++

Lists tools and resources that are used in the process, but that aren't
used up. Tools are listed in the same way as inputs, e.g.::

  object ? (category ~ WaterHeater & achievableHeat >= 100
            & heatableVolume >= 2);

(A water heater than can heat 2 liters of water (or more) to 100 degree
Celsius (or more), required for ca. 15 minutes.)

Additional property:

* time (time?): an estimate of the time for which the tool is
  required--useful e.g. for cost calculations if a tool is shared or rented
  on a temporal basis.

Constraints
+++++++++++

Lists conditions that must be true for the process to be performed as
expected. Described in the same way as inputs, e.g.::

  constraint ? (10 <= EnvironmentTemperature <= 35)

(The environmental temperature must be between 10 and 35 °C.)

Implementation note: input, tools, and constraints can be stored as "saved
queries" in the database.

Output
++++++

The output describes the objects that will be created as a result of the
process, if any. Output is specified in a simple declarative language::

  object::
    category: WaterBoiler
    achievableHeat: {60, 80, 90, 100}  # a list
    heatableVolume: 0..3             # a range
    power: 700
    weight: 2.8
    width: 0.28
    depth: 0.2
    height: 0.29

If an *id* is specified for the object (recommended), this means that all
the object properties not explicitly defined can be determined by looking
up the object in the database.

(A water boiler that can heat up to 3 liters of water to 60, 80, 90, or 100
°C, needs 700 W, weights 2.8 kg etc.)

For processes that don't *create* any objects, but only repair, maintain,
or use them, no output will be defined. Processes that dismantle objects
should list the resulting remains or waste as output.

Operations
++++++++++

TODO document new query-like syntax:

Most operations will either be "machine x should run file y" or "the user
shall do as described in file z". And these operations can be ordered or
unordered (order of execution matters, or it doesn't) or there may be
alternatives (if the machine understands Polyps, it should execute this
file, otherwise we have prepared a STL alternative). So my idea is to have
something like the query language we use for defining dependencies in order
to define such operations.

Idea for a basic building block:

* toolname: "filename" -- run file <filename> on tool <toolname>

With about 3 special instructions:

* run: "filename" -- run the file in this computer (e.g. a Python script)
* read: "filename" -- the human user should read the file (e.g. a HTML
  file) and follow the instructions therein. If two (or more) alternative
  versions of the file exist, they should be listed as alternatives::

    read: (filename.html | filename.txt)

  Note: recommended documentation format is HTML; alternatives are open
  file formats such as plain text, PDF, and ODT (plaintext documentation
  can be generated from HTML calling e.g. ``lynx -dump -nolist`` or
  ``elinks -no-numbering -no-references``, Markdown or reStructuredText
  make it possible to go into the other direction). HTML files shouldn't
  contain any scripts; they should be run through `HTML Tidy
  <http://tidy.sourceforge.net/>`_ to ensure well-formedness.
* do: "blah blah blah" -- also instructions for the user, but specified
  inline as a string instead of a separate file (for short operations)

These blocks can then be combined:

* A; B -- execute first A, then B (order matters)
* A & B -- execute A and B (order doesn't matter)
* A | B -- execute A or B (alternatives). Recommended reading: try the
  first which works (if the tool doesn't understand the file format
  specified in A, try B instead)

TODO largely obsolete:

This is the core of the process description: the list of operations to be
performed as part of the process. Operations are partially ordered: some
must be performed sequentially, others can be performed simultaneously or
in arbitrary order.

For each operation, there is an *agent* that should realize the
operation--either one of the *tools* required for the process (or, in some
cases, one of the *inputs* defined?), or a human.

Operations will ofter refer to one *files* attached to the process: CNC
router should execute the toolpath defined in file X, human should bolt the
components together as shown in PDF file Y, etc.

*Variables* can be assigned or reassigned by specifying the variable name,
followed by ":=" and an expressions (as in Polyps)::

  varname: 1 + 2;

Operations are arranged in *blocks* (enclosed in curly brackets) that can
be named and/or annotated with a keyword.

Keyword blocks
^^^^^^^^^^^^^^

Keywords (preceding the opening bracket) either specify the relation
between the operations in the block:

sequential
  Operations must be executed in the defined order--this is the default.

parallel
  Operations can be executed in parallel or in arbitrary order.

alternative
  It's sufficient to execute on of the operations.

Samples::

  parallel {  # execute these operations in any order
    doThis();
    doThat();
    doSomethingElse();
  }

  sequential {  # You can use this inside a parallel block. Otherwise you
              # won't need it, as all other blocks are sequential by
              # default.
    doThis();
    doThat();
    doSomethingElse();
  }

  alternative {  # select one of those processes
    doThis();
    doThat();
    doSomethingElse();
  }

Or they specify that the block should be executed zero, once, or possibly
several times depending on the value of an expression; or that it
should be executed for all the items in a list:

if *expression*
  Executes the block if *expression* evaluates to true; optionally followed
  by an *elif* or *else* block.

elif *expression*
  Executes the block if *expression* evaluates to true and if none of the
  preceding *if* and *elif* blocks was executed; only allowed immediately
  after an *if* and *elif* block.

else
  Executes the block if none of the preceding *if* and *elif* blocks was
  executed; only allowed immediately after an *if* and *elif* block.

while *expression*
  The block is executed any number of times, as long as *expression*
  evaluates to true.

for *varname* in *list*
  Executes the block for each of the members in the *list*, setting
  *varname* to the value of the currently selected list member.

for *varname* in *range*
  Executes the block for each integer value within the specified range,
  setting *varname* to the current value; both the lower and the upper
  limits of the range can be either inclusive or exclusive; both limits of
  the range must be integer values. Specifying a number *n* instead of a
  range is identical to specifying the range *[0..n[* (the loop is executed
  *n* times, indexing starts from 0).

Samples::

  if *condition* {
    doThis();
    doThat();
    doSomethingElse();
  } elif *another-condition* {
    doAnotherThing()
  } else {
    doSomethingStrange()
  }

  while *condition* {
    doThis();
    doThat();
    doSomethingElse();
  }

  # The argument of a for loop is a list...
  for file in [fileA, fileB, fileC] {  # do this for each of the 3 files
    doThis();
    doThat();
  }

  # ...or a range...
  for i in [1..10] { # repeat 10 times (increasing the value of i)
    doThis();
    doThat();
  }

  # ...or a number...
  for i in 10 { # repeat 10 times, but this time counting from 0
    doThis();
    doThat();
  }

Functions (Named Blocks)
^^^^^^^^^^^^^^^^^^^^^^^^

Functions (named blocks) are defined by prepending a function name followed
by a (possibly empty) parameter list before the actual block, separated by
":=". Parameters are comma-separated and enclosed in parentheses.

Functions must be declared at the highest level, they can't be nested within
another block. Function blocks are initially skipped, they must be
explicitly invoked to be executed. Functions can only be invoked after they
have been defined.

Samples for defining and invoking functions::

  # Defining a function with one parameter
  sharpenTheSaw(sharpness) := {
    ...
  }

  # Defining a parameterless function:
  prepareTools() := parallel {
    # function name and keyword can be combined
    # (it does not matter in which order the tools are prepared)
    sharpenTheSaw(10);
    fillWaterInTheHeater();
    preheatTheFabber();
  }

  # Defining a function with multiple parameters
  buildLegs(numOfLegs, kindOfWood, diameter) := {
    ...
  }

Each process must have exactly one function named *main*; the process is
run be executing this function. If the process accepts parameters (cf.
below), the *main* function must accept each of these parameters as
parameter (order doesn't matter, additional parameters are not allowed); if
the process doesn't support parametrization, *main* must not accept any
parameters.

Built-in Functions
^^^^^^^^^^^^^^^^^^

The following functions are built in:

TODO list: "do", "query", "[object.]run", and "[object.eval]"; return
values can be stored using ":=".

Parameters
++++++++++

TODO can be specified as ranges and lists, but how to distinguish from
normal ranges and lists? Use "?=" instead of ":=" ?

It should be possible for a process to accept *parameters* that influence
the process--for example, if you built a chair, you can configure the exact
length of the legs, specify whether it should have a cushion, select the
color etc.

For each parameter, the supported range or enumeration of values should be
predefined; the user then chooses among the available options.

The choice of parameter values can influence the other elements of the
process--exact input requirements and output specification will depend on
them; some of the operations will change to reflect to them; possibly, the
tools required will change too.

When storing options in the DB, the whole range or enum should be stored in
order to be searchable (e.g. a chair that can be made in any color with
legs between 35 cm and 80 cm should match a search for a red chair with 50
cm legs.) That's more difficult for input/tool requirements, however (we
can calculate and store how much material a 35 cm or a 80 cm chair would
need, but we can't precalculate and store such information for *all*
possible values). A possible, though imperfect solution would be to store
such information for the *minimum* and *maximum* values of numeric
parameters, and for a *default* value for enum parameters; and to calculate
the exact values on demand.

Example of declaring parameters::

  # leg length is between 35 cm and 80 cm
  leg-length: 0.35..0.80;
  # six different colors are available
  color: {red, green, blue, yellow, black, white};

Example of selecting parameters--syntax is identical to the syntax used for
defining inputs::

  # we want a blue chair with 50 cm legs
  leg-length = 0.5 & color = "blue";

TODO calculate output parameters to input parameters and vice versa:
*parametrize,* optionally *invParametrize*.

Object Database
~~~~~~~~~~~~~~~

TODO Describe how objects and processes are stored in the DB.

Tangible Bit Object Description
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The *Tangible Bit Object* file format (extension: *.tbob*) allows
extracting objects with their relevant processes from the database and
sharing them computers and users. A TBOB file can contain one or many
objects with their relevant processes.

A TBOB package is a ZIP file (like formats such as ODT and EPUB).

First-level directories: the file contains one directory for objects and
one for each type of processes it contains::

  objects
  build
  setup
  use
  maintain
  repair
  replace

(Empty directories can be omitted.)

Second-level directories: Each object and each process is stored in a
subdirectory of the corresponding folder, using the object/process ID as
directory name (e.g. ``objects/com.example.coffeemaker``).

Each object is represented by three simple text files, written in the
Tangible Bit Declaration Language:

* properties.tdl: contains the object properties
* processes.tdl: index of processes associated with the object
* files.tdl: index of files associated with the object

-> TODO Or probably just a single file ``object.tb`` defining the object
properties (without any sections).

Each process is represented by five simple text files:

* properties.tdl: contains the process metadata
* dependencies.tql: lists the input, tools, and constraints required
  (written in Tangible Bit Query Language)
* result.tdl: defines the output and the allowed parameter settings
* operations.top: defines the list of operations to be performed (written
  in Tangible Bit Operations Language)
* files.tdl: index of files associated with the process

-> TODO Or probably just a single file ``process.tb`` with up to 7
sections:

* [properties]: defines the process properties
* [constraints]: the constraints that must be fulfilled in order to run the
  process (optional)
* [tools]: the required tools (optional)
* [input]: the required input (optional)
* [output]: the output of the process (optional)
* [operations]: list of operations (instructions to be followed by a human
  or a machine) (optional)
* [files]: other files associated with the process (optional)

TODO explain "dirball" concept for instructions (e.g. HTML ball).

If an object or process contains files, they are stored in a third-level
folder named ``files``.

TODO mimetype file?; internationalization/translated strings?

Sample directory structure::

  objects/
    com.example.coffeemaker/
      properties.tdl
      processes.tdl
      files.tdl
      files/
        thumbnail.gif
        frontview.jpg
  build/
    com.example.coffeemaker.buildit/
      properties.tdl
      dependencies.tql
      result.tdl
      operations.top
      files.tdl
      files/
        blueprint.iges

TODO Ensure that it's OK to package GPL'ed software with non-GPL'ed content
in a single ZIP file (should be).

To Do
~~~~~

* Decide on syntax to use in *formattedtext* (Markdown or WikiCreole?).
* Write sample object package (Drawdio?) and tutorial/overview document on
  documenting and packing objects.
* Get in dialog with people creating and using free designs about what they
  need and whether our approach suits them.
* Document format of declarations (DecL language) and write parser; define
  literal form / parse expression of the *basetypes*.
* Write database generator that reads the type declarations and creates or
  updates the database scheme accordingly.
* Define and publish controlled vocabulary of recommended license names and
  of the roles of files.
* See TODOs above.