Task 617: .ROB File Format
Task 617: .ROB File Format
1. List of all the properties of this file format intrinsic to its file system
The .rob file format is a text-based format used in the Klamp't robotics library for defining robot models. It consists of key-value lines where each key represents a property, followed by its values. Properties are intrinsic to the format's structure for specifying kinematics, dynamics, geometry, joints, drivers, and other robot attributes. Based on the specifications, the complete list of properties is:
- links: Specifies the names of the robot's links.
- parents: Specifies the parent indices for each link.
- jointtype: Specifies the type of joint for each degree of freedom (DOF), e.g., 'r' for revolute or 'p' for prismatic.
- tparent: Specifies the relative rigid transforms between each link and its parent (rotation matrix and translation).
- alpha, a, d, theta: Denavit-Hartenberg (D-H) parameters for joint configuration.
- alphadeg, thetadeg: D-H parameters in degrees.
- axis: Specifies the axis of rotation or translation for each DOF.
- qmin, qmindeg: Lower limits for joint configurations (in radians or degrees).
- qmax, qmaxdeg: Upper limits for joint configurations (in radians or degrees).
- q, qdeg: Initial joint configuration values (in radians or degrees).
- translation: Shifts the base link's position.
- rotation: Rotates the base link using a rotation matrix.
- scale: Scales the entire robot model.
- mount: Mounts a sub-robot or geometry to a link, with optional transform and name prefix.
- mass: Masses for each link.
- automass: Automatically computes mass properties from geometry, with optional surface fraction.
- com: Centers of mass for each link.
- inertiadiag: Diagonal elements of inertia matrices (assuming zero off-diagonals).
- inertia: Full 3x3 inertia matrices for each link.
- velmin, velmindeg: Lower velocity limits (in radians/s or degrees/s).
- velmax, velmaxdeg: Upper velocity limits (in radians/s or degrees/s).
- accmax, accmaxdeg: Absolute acceleration limits (in radians/s² or degrees/s²).
- torquemax: Torque limits for each DOF.
- powermax: Power limits for each DOF.
- autotorque: Automatically sets torque limits based on descendant links.
- geometry: File paths to geometry files for each link.
- geomscale: Scales for link geometries.
- geomtransform: 4x4 transformation matrices for link geometries.
- geommargin: Collision margins for geometries.
- noselfcollision: Pairs of links to disable self-collision checks.
- selfcollision: Pairs of links to enable self-collision checks.
- joint: Defines joint types (e.g., normal, spin, weld, floating) for links or ranges.
- driver: Defines driver types and parameters.
- servoP: Position gains for drivers.
- servoI: Integral gains for drivers.
- servoD: Derivative gains for drivers.
- dryFriction: Dry friction coefficients for drivers.
- viscousFriction: Viscous friction coefficients for drivers.
- property: Custom properties like sensors or controller, specified as files or XML strings.
These properties are parsed from lines in the file, with support for comments (#), line continuations (), and quoted strings for values with spaces.
2. Two direct download links for files of format .ROB
- https://raw.githubusercontent.com/krishauser/Klampt-examples/master/data/robots/athlete.rob
- https://raw.githubusercontent.com/krishauser/Klampt-examples/master/data/robots/baxter.rob
3. Ghost blog embedded html javascript that allows a user to drag n drop a file of format .ROB and it will dump to screen all these properties
4. Python class that can open any file of format .ROB and decode read and write and print to console all the properties from the above list
import json
import os
class RobFile:
def __init__(self):
self.properties = {}
def load(self, filename):
if not os.path.exists(filename):
raise FileNotFoundError(f"File {filename} not found")
with open(filename, 'r') as f:
text = f.read()
lines = text.split('\n')
current_line = ''
for line in lines:
line = line.strip()
if line.startswith('#') or not line:
continue
if line.endswith('\\'):
current_line += line[:-1].strip() + ' '
continue
current_line += line
parts = []
i = 0
while i < len(current_line):
if current_line[i] == '"':
j = current_line.find('"', i + 1)
parts.append(current_line[i+1:j])
i = j + 1
else:
j = i
while j < len(current_line) and current_line[j] not in ' \t':
j += 1
parts.append(current_line[i:j])
i = j
while i < len(current_line) and current_line[i] in ' \t':
i += 1
if parts:
key = parts[0]
values = parts[1:]
self.properties[key] = values
current_line = ''
def print_properties(self):
print(json.dumps(self.properties, indent=4))
def write(self, filename):
with open(filename, 'w') as f:
for key, values in self.properties.items():
line = key
for value in values:
if ' ' in value:
line += f' "{value}"'
else:
line += f' {value}'
f.write(line + '\n')
# Example usage:
# rob = RobFile()
# rob.load('example.rob')
# rob.print_properties()
# rob.write('output.rob')
5. Java class that can open any file of format .ROB and decode read and write and print to console all the properties from the above list
import java.io.*;
import java.util.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class RobFile {
private Map<String, List<String>> properties = new HashMap<>();
public void load(String filename) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line;
StringBuilder currentLine = new StringBuilder();
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.startsWith("#") || line.isEmpty()) continue;
if (line.endsWith("\\")) {
currentLine.append(line.substring(0, line.length() - 1).trim()).append(" ");
continue;
}
currentLine.append(line);
List<String> parts = parseLine(currentLine.toString());
if (!parts.isEmpty()) {
String key = parts.get(0);
List<String> values = parts.subList(1, parts.size());
properties.put(key, values);
}
currentLine.setLength(0);
}
reader.close();
}
private List<String> parseLine(String input) {
List<String> parts = new ArrayList<>();
int i = 0;
while (i < input.length()) {
if (input.charAt(i) == '"') {
int j = input.indexOf('"', i + 1);
if (j == -1) break;
parts.add(input.substring(i + 1, j));
i = j + 1;
} else {
int j = i;
while (j < input.length() && !Character.isWhitespace(input.charAt(j))) j++;
parts.add(input.substring(i, j));
i = j;
}
while (i < input.length() && Character.isWhitespace(input.charAt(i))) i++;
}
return parts;
}
public void printProperties() {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println(gson.toJson(properties));
}
public void write(String filename) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
for (Map.Entry<String, List<String>> entry : properties.entrySet()) {
StringBuilder sb = new StringBuilder(entry.getKey());
for (String value : entry.getValue()) {
sb.append(value.contains(" ") ? " \"" + value + "\"" : " " + value);
}
writer.write(sb.toString());
writer.newLine();
}
writer.close();
}
// Example usage:
// public static void main(String[] args) throws IOException {
// RobFile rob = new RobFile();
// rob.load("example.rob");
// rob.printProperties();
// rob.write("output.rob");
// }
}
6. Javascript class that can open any file of format .ROB and decode read and write and print to console all the properties from the above list
const fs = require('fs'); // For Node.js environment
class RobFile {
constructor() {
this.properties = {};
}
load(filename) {
const text = fs.readFileSync(filename, 'utf8');
const lines = text.split('\n');
let currentLine = '';
for (let line of lines) {
line = line.trim();
if (line.startsWith('#') || line === '') continue;
if (line.endsWith('\\')) {
currentLine += line.slice(0, -1).trim() + ' ';
continue;
}
currentLine += line;
const parts = currentLine.match(/"[^"]*"|\S+/g) || [];
const cleanedParts = parts.map(p => p.replace(/"/g, ''));
if (cleanedParts.length > 0) {
const key = cleanedParts[0];
const values = cleanedParts.slice(1);
this.properties[key] = values;
}
currentLine = '';
}
}
printProperties() {
console.log(JSON.stringify(this.properties, null, 2));
}
write(filename) {
let content = '';
for (const [key, values] of Object.entries(this.properties)) {
let line = key;
for (const value of values) {
line += value.includes(' ') ? ` "${value}"` : ` ${value}`;
}
content += line + '\n';
}
fs.writeFileSync(filename, content);
}
}
// Example usage:
// const rob = new RobFile();
// rob.load('example.rob');
// rob.printProperties();
// rob.write('output.rob');
7. Write a c class that can open any file of format .ROB and decode read and write and print to console all the properties from the above list
Since C does not have built-in classes like object-oriented languages, the following implements a struct RobFile with associated functions for loading, printing, and writing. It uses dynamic memory for flexibility. Compile with a C compiler (e.g., gcc) and link if needed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_LINE 4096
#define MAX_KEYS 100
#define MAX_VALUES 1000
typedef struct {
char *key;
char **values;
int value_count;
} Property;
typedef struct {
Property properties[MAX_KEYS];
int prop_count;
} RobFile;
void init_rob_file(RobFile *rob) {
rob->prop_count = 0;
}
void free_rob_file(RobFile *rob) {
for (int i = 0; i < rob->prop_count; i++) {
free(rob->properties[i].key);
for (int j = 0; j < rob->properties[i].value_count; j++) {
free(rob->properties[i].values[j]);
}
free(rob->properties[i].values);
}
}
int load_rob_file(RobFile *rob, const char *filename) {
FILE *fp = fopen(filename, "r");
if (!fp) return -1;
char line[MAX_LINE];
char current_line[MAX_LINE] = {0};
while (fgets(line, MAX_LINE, fp)) {
char *trimmed = line;
while (isspace(*trimmed)) trimmed++;
if (*trimmed == '#' || *trimmed == '\0') continue;
size_t len = strlen(trimmed);
if (trimmed[len - 1] == '\n') trimmed[--len] = '\0';
if (trimmed[len - 1] == '\\') {
trimmed[len - 1] = ' ';
strcat(current_line, trimmed);
continue;
}
strcat(current_line, trimmed);
// Parse parts
char *parts[MAX_VALUES];
int part_count = 0;
char *p = current_line;
while (*p) {
while (isspace(*p)) p++;
if (!*p) break;
if (*p == '"') {
p++;
char *start = p;
while (*p && *p != '"') p++;
if (*p) p++;
int plen = p - start - 1;
parts[part_count] = malloc(plen + 1);
strncpy(parts[part_count++], start, plen);
parts[part_count - 1][plen] = '\0';
} else {
char *start = p;
while (*p && !isspace(*p)) p++;
int plen = p - start;
parts[part_count] = malloc(plen + 1);
strncpy(parts[part_count++], start, plen);
parts[part_count - 1][plen] = '\0';
}
}
if (part_count > 0) {
Property *prop = &rob->properties[rob->prop_count++];
prop->key = parts[0];
prop->values = malloc((part_count - 1) * sizeof(char*));
prop->value_count = part_count - 1;
for (int i = 1; i < part_count; i++) {
prop->values[i - 1] = parts[i];
}
}
current_line[0] = '\0';
}
fclose(fp);
return 0;
}
void print_rob_properties(const RobFile *rob) {
printf("{\n");
for (int i = 0; i < rob->prop_count; i++) {
const Property *prop = &rob->properties[i];
printf(" \"%s\": [", prop->key);
for (int j = 0; j < prop->value_count; j++) {
printf("\"%s\"", prop->values[j]);
if (j < prop->value_count - 1) printf(", ");
}
printf("]");
if (i < rob->prop_count - 1) printf(",\n");
else printf("\n");
}
printf("}\n");
}
int write_rob_file(const RobFile *rob, const char *filename) {
FILE *fp = fopen(filename, "w");
if (!fp) return -1;
for (int i = 0; i < rob->prop_count; i++) {
const Property *prop = &rob->properties[i];
fprintf(fp, "%s", prop->key);
for (int j = 0; j < prop->value_count; j++) {
if (strchr(prop->values[j], ' ')) {
fprintf(fp, " \"%s\"", prop->values[j]);
} else {
fprintf(fp, " %s", prop->values[j]);
}
}
fprintf(fp, "\n");
}
fclose(fp);
return 0;
}
// Example usage:
// int main() {
// RobFile rob;
// init_rob_file(&rob);
// if (load_rob_file(&rob, "example.rob") == 0) {
// print_rob_properties(&rob);
// write_rob_file(&rob, "output.rob");
// }
// free_rob_file(&rob);
// return 0;
// }