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:

[meta]
prefix: com.tangiblebit.type # prefix used for all IDs in this document
id: object
description: The root of the object hierarchy.

[req] # Required properties
name(freetext): An informal name of the object.

id(string):
  An ID uniquely identifying the object; to avoid name clashes, you should
  use "reverse domain name notation" (like Java package) starting with a
  domain you control. Sample: com.example.coffeemaker if you own the
  example.com domain.

summary(freetext): A short (one line) description of what the object is and
  what it can be used for.

license(string):
  The license under which the object is made available (must be compatible
  with CC-SA-BY or a free software/open source license in order to allow
  inclusion in the TB object database). On the TBit website there is
  controlled vocabulary of license names that should be used in this field
  and in the *softwareLicense* field.

[opt] # Optional properties
homepage(string): The homepage of the object.

orderpage(string): A web page where prebuilt copies of the object or kits
  or components can be ordered.

producer(string): The company or organization typically (or initially)
  producing the object.

description(freetext):
  A longer description of the object.

lastModified(timestamp): Timestamp showing when the object metadata or the
  files or processes connected with the object where last modified.

weight(mass):
  The weight of the object (set to 0 if this is a non-material object).

width(length): The total width of the object, when fitting it into a box (0
  if this is a non-material object).

depth(length): The total depth of the object, when fitting it into a box (0
  if this is a non-material object).

height(length): The total height of the object, when fitting it into a box
  (0 if this is a non-material object).

softwareLicense(string):
  The license under which the software related to the object is made
  available (must be compatible with CC-SA-BY or a free software/open
  source license in order to allow inclusion in the TB object
  database). If omitted, the value given in the *license* field is used
  instead.

[list] # Properties occurring once or more
category(identifier): List of categories the object belongs to.

maintainer(contact):
  List of people to contact regarding questions about the object.

replaces(string):
  List of object IDs this object is meant to replace/make obsolete.

[optlist] # Properties occurring any number of times
author(contact):
  List of the people which created/packaged the object.

thumbnail(file): List of small visual depictions of the object (pointers to
  image files--stored in the *thumbnails* folder).

file(file): List of files associated with the object (pointers to files
  stored in the *files* folder).

# Lists of processes associated with the object
build:
  List of processes (IDs) explaining how to build/produce the object.

setup:
  List of processes (IDs) explaining how to setup the object prior to using
  it (comes between build and usage, and can optionally later be repeated
  when necessary.) Sample: program channel list on a TV set.

use: List of processes (IDs) explaining how to use the object, in general
  or for some specific purpose.

dismantle: List of processes (IDs) explaining how to dismantle/disassemble
  the object.

maintain:
  List of processes (IDs) explaining how to maintain the object--describes
  operations that need to be performed regularly or occasionally to keep
  the object in good order. Sample: change oil in a car.

repair: List of processes (IDs) explaining how to repair the object or some
  parts of it.

replace: List of processes (IDs) explaining how to replace same part of the
  object.

TODO include parsed and beautified version of files instead.

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

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:

# The basic types that can be used for atomic fields. Types not defined
# here are complex types, made up of several atomic or complex types.

int: An integer number. External form: as in TDF.

float: A floating point number. External form: as in TDF.

bool: A Boolean value, either "true" or "false".

string: A string. Use this base type for free-form strings that are not
  meant to be localized. Strings can contain arbitrary Unicode characters.
  External form: as in TDF.

timestamp: A point in time. External form: like the `YAML timestamp
  <http://yaml.org/type/timestamp.html>`_ type.

identifier(string):
  An identifier, made up of alphanumeric characters and underscores.

freetext(string):
  Text that can be localized (translated in other languages).

# Unit types

capacitance(float):
  An electric capacitance, measured by default in farad (F).

length(float): A length, measured by default in meter (m).

mass(float): A mass, measured by default in kilogram (kg).

power(float): A (physical) power, measured by default in watt (W).

resistance(float):
  A electrical resistance or impedance, measured by default in ohm (Ω).

voltage(float): A voltage (electrical potential difference), measured by
  default in volt (V).

# CSV types contain several pieces of information wrapped in a single
# string, formatted as a CSV fragment: items are comma-separated; if an
# item contains commas or newlines, it must be enclosed in quotation marks.
# CSV types are defined by giving a comma-separated list of field names in
# parentheses; each followed by "=" and the field type; a "?" preceding the
# field name marks the field as optional (may be omitted or empty).
contact(?givenName=string, ?surname=string, ?emailAddress=string):
  Provides a minimum of contact information about a person: name and
  e-mail address.

All properties that require a unit come with a "natural unit" taken, when possible, from the 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

[meta]
prefix: com.tangiblebit.type # prefix used for all IDs in this document
id: process
description: A process description

[req] # Required properties
name(freetext): An informal name and short summary of the process.

id(string):
  An ID uniquely identifying the process. Tip: derive from the ID of the
  corresponding object (e.g. "com.example.coffeemaker.buildit" for a
  process documenting how to build a "com.example.coffeemaker" object).

license(string):
  The license under which the process is made available (must be compatible
  with CC-SA-BY or a free software/open source license in order to allow
  inclusion in the TB process database). On the TBit website there is
  controlled vocabulary of license names that should be used in this field
  and in the *softwareLicense* field.

[opt] # Optional properties
description(freetext): A description of the process.

homepage(string): The homepage of the process.

lastModified(timestamp):
  Timestamp showing when the process description or the files connected
  with the process were last modified.

softwareLicense(string):
  The license under which the software related to the process is made
  available (must be compatible with CC-SA-BY or a free software/open
  source license in order to allow inclusion in the TB process database).
  If omitted, the value given in the *license* field is used instead.

[list] # Properties occurring once or more
maintainer(contact): List of people to contact regarding questions about
  the process (typically same as for the corresponding object).

[optlist] # Properties occurring any number of times
author(contact): List of the people which created/packaged the process
  (typically same as for the corresponding object).

replaces(string):
  List of process IDs this process is meant to replace/make obsolete.

thumbnail(file): A list of small visual depictions of the process (pointers
  to image files--stored in the *thumbnails* folder).

file(file):
  List of files that are helpful in order to better understand the process,
  but aren't generally necessary in order to execute it (pointers to files
  stored in the *files* folder).

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-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 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:

-> 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:

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

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