Robot profiles

A robot profile (bot.robot-profile@1) is the contract between a robot and its panel. The panel is a function of the profile: a new robot needs a profile, not code. Profiles ship as server/profiles/*.json, are validated by the loader, and are served at GET /api/v1/profiles.

Fields

  • id — the profile's name, ^[a-z][a-z0-9._-]{1,63}$ (for example sim.rover).
  • version — a positive integer; a new profile is a new version.
  • name — what the owner sees. vendor, description — optional.
  • kind — onboard, bridge or server (see Write a driver).
  • capabilities — one or more of the registry: drive.differential, drive.mecanum, servo.pan_tilt, head, lift, lights.rgb, lights.backpack, lights.cube, speaker.horn, speaker.say, display.text, sensor.ultrasonic, sensor.line, sensor.cliff, sensor.pickup, battery, ptz, camera, relay. A typo is refused at load.
  • variants — optional: one profile, several wheel layouts.
  • mapping — { "driver": … }, one of pca9685, ads7830, cozmo, looi, onvif, sim, relay, plus the driver's own hardware map (addresses, channels).
  • commands — what the driver accepts, keyed by kind: drive and ptz ({ axes: { <axis>: [min, max] } }), actuator ({ names: { <name>: { type: number|rgb|tone|bool, … } } }), say, display, button and point. Every profile also takes halt. The gate allows only the kinds declared here and builds every value from it.
  • widgets — the panel, in order. Each is { type, capability?, label?, command? }; types are drive, pan-tilt, servo, lights, horn, speaker, display, telemetry, battery, latency, ptz, camera, head, lift, buttons, video_click. A widget that sends commands names them in command, checked against commands at load.
  • camera — optional: { transport: "whip"|"onvif"|"rtsp", resolution }.
  • limits — optional, with defaults: max_speed and max_turn (1), max_command_ms (300), heartbeat_ms (1000). Positive; the stricter of these and the server's own limits applies.

The schema is bot.robot-profile@1; capability and widget names are open strings checked against the registries in server/profiles/index.js, so a new one is one line there, never a schema change.

A full example

The simulated rover (sim.rover), the profile the in-process simulator on this site runs:

{
  "id": "sim.rover",
  "version": 2,
  "name": "Simulated rover",
  "vendor": "OpenVibe",
  "kind": "server",
  "description": "A differential-drive rover in a small arena, simulated by OpenVibe.Bot (or in your browser at /try): a front camera, an ultrasonic range finder, three line sensors over a strip of tape, a battery, RGB headlights and a horn, driven through the same gate and profile as real hardware.",
  "capabilities": [
    "drive.differential",
    "camera",
    "sensor.ultrasonic",
    "sensor.line",
    "battery",
    "lights.rgb",
    "speaker.horn"
  ],
  "mapping": {
    "driver": "sim"
  },
  "commands": {
    "drive": {
      "axes": {
        "throttle": [
          -1,
          1
        ],
        "steer": [
          -1,
          1
        ]
      }
    },
    "actuator": {
      "names": {
        "headlights": {
          "type": "rgb"
        },
        "horn": {
          "type": "tone",
          "hz": [
            220,
            880
          ]
        }
      }
    }
  },
  "widgets": [
    {
      "type": "camera",
      "capability": "camera",
      "label": "Front camera",
      "order": 1
    },
    {
      "type": "drive",
      "capability": "drive.differential",
      "label": "Drive",
      "order": 2,
      "command": {
        "kind": "drive"
      }
    },
    {
      "type": "telemetry",
      "capability": "sensor.ultrasonic",
      "label": "Distance ahead",
      "order": 3
    },
    {
      "type": "telemetry",
      "capability": "sensor.line",
      "label": "Line sensors",
      "order": 4
    },
    {
      "type": "battery",
      "capability": "battery",
      "label": "Battery",
      "order": 5
    },
    {
      "type": "lights",
      "capability": "lights.rgb",
      "label": "Headlights",
      "order": 6,
      "command": {
        "kind": "actuator",
        "names": [
          "headlights"
        ]
      }
    },
    {
      "type": "horn",
      "capability": "speaker.horn",
      "label": "Horn",
      "order": 7,
      "command": {
        "kind": "actuator",
        "names": [
          "horn"
        ]
      }
    },
    {
      "type": "latency",
      "label": "Latency",
      "order": 8
    }
  ],
  "camera": {
    "transport": "whip",
    "resolution": "640x360"
  },
  "limits": {
    "max_speed": 1,
    "max_turn": 1,
    "max_command_ms": 300,
    "heartbeat_ms": 1000
  }
}

Validate a profile

Paste a profile JSON. It is run through exactly the checks a shipped profile gets.

Tools can POST the profile as JSON to /api/v1/profiles/validate and read { valid, problems } back.

The Node and its bundled drivers are in OpenVibers/OpenVibe.Node; the full protocol is protocol.md and the plugin contract is plugins.md.