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 examplesim.rover).version— a positive integer; a new profile is a new version.name— what the owner sees.vendor,description— optional.kind—onboard,bridgeorserver(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 ofpca9685,ads7830,cozmo,looi,onvif,sim,relay, plus the driver's own hardware map (addresses, channels).commands— what the driver accepts, keyed by kind:driveandptz({ axes: { <axis>: [min, max] } }),actuator({ names: { <name>: { type: number|rgb|tone|bool, … } } }),say,display,buttonandpoint. Every profile also takeshalt. 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 aredrive,pan-tilt,servo,lights,horn,speaker,display,telemetry,battery,latency,ptz,camera,head,lift,buttons,video_click. A widget that sends commands names them incommand, checked againstcommandsat load.camera— optional:{ transport: "whip"|"onvif"|"rtsp", resolution }.limits— optional, with defaults:max_speedandmax_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.