Utilities API
Helper functions for parsing and transforming data between different coordinate systems and formats.
Parsing Functions
parseVector(vec: string): BABYLON.Vector3
Parses a space-separated string into a Babylon.js Vector3.
Parameters:
- vec
: string - Space-separated coordinates (e.g., "1.5 0.0 0.3")
Returns: BABYLON.Vector3 - Parsed vector
Throws: Error if string doesn't contain exactly 3 values
Example:
import { parseVector } from '@ranchhandrobotics/babylon_ros';
// Parse position from URDF
const positionStr = "1.0 0.5 0.25";
const position = parseVector(positionStr);
console.log(position); // Vector3(1.0, 0.5, 0.25)
// Use in transform
joint.origin = parseVector("0 0 0.1");
parseRPY(rpy: string): BABYLON.Vector3
Parses a roll-pitch-yaw rotation string into a Babylon.js Vector3.
Parameters:
- rpy
: string - Space-separated RPY angles in radians (e.g., "0 0 1.57")
Returns: BABYLON.Vector3 - RPY rotation vector
Note: Maintains ROS convention (Roll, Pitch, Yaw) in Vector3 components
Example:
import { parseRPY } from '@ranchhandrobotics/babylon_ros';
// Parse rotation from URDF
const rpyStr = "0 0 1.5708"; // 90 degrees yaw
const rotation = parseRPY(rpyStr);
console.log(rotation); // Vector3(0, 0, 1.5708)
// Use in joint
joint.rpy = parseRPY("0.1 0.2 0.3");
parseColor(color: string): BABYLON.Color4
Parses an RGBA color string into a Babylon.js Color4.
Parameters:
- color
: string - Space-separated RGBA values (0.0 to 1.0, e.g., "1.0 0.0 0.0 1.0")
Returns: BABYLON.Color4 - Parsed color
Throws: Error if string doesn't contain exactly 4 values
Example:
import { parseColor } from '@ranchhandrobotics/babylon_ros';
// Parse material color from URDF
const colorStr = "0.8 0.2 0.1 1.0"; // Orange
const color = parseColor(colorStr);
console.log(color); // Color4(0.8, 0.2, 0.1, 1.0)
// Use in material
material.color = parseColor("1.0 0.0 0.0 0.8"); // Semi-transparent red
Transformation Functions
applyRotationToTransform(transformNode: BABYLON.TransformNode, vec: BABYLON.Vector3): void
Applies roll-pitch-yaw rotation to a transform node using the correct order.
Parameters:
- transformNode
: BABYLON.TransformNode - The node to rotate
- vec
: BABYLON.Vector3 - RPY rotation values in radians
Behavior: - Applies rotations in the correct order: Yaw (Z), then Pitch (Y), then Roll (X) - Handles ROS to Babylon.js coordinate system conversion - Modifies the transform node in place
Example:
import { applyRotationToTransform } from '@ranchhandrobotics/babylon_ros';
// Create transform node
const transform = new BABYLON.TransformNode("joint_transform", scene);
// Apply 90-degree yaw rotation
const rpy = new BABYLON.Vector3(0, 0, Math.PI/2);
applyRotationToTransform(transform, rpy);
// Transform is now rotated 90 degrees around Z-axis
Usage Examples
URDF Data Parsing
// Typical URDF parsing workflow
const urdfOrigin = "1.0 0.5 0.25"; // Position
const urdfRPY = "0 0 1.5708"; // 90° yaw
const urdfColor = "0.8 0.2 0.1 1.0"; // Orange color
// Parse into Babylon.js types
const position = parseVector(urdfOrigin);
const rotation = parseRPY(urdfRPY);
const color = parseColor(urdfColor);
// Apply to robot components
joint.origin = position;
joint.rpy = rotation;
material.color = color;
Complete Joint Setup
// Joint configuration from URDF attributes
const joint = new Joint();
joint.name = "shoulder_joint";
joint.origin = parseVector("0.1 0 0.2"); // 10cm forward, 20cm up
joint.rpy = parseRPY("0 0 0"); // No rotation
joint.axis = parseVector("0 1 0"); // Y-axis rotation
// Create transform and apply rotation
joint.create(scene, materialMap);
if (joint.transform) {
applyRotationToTransform(joint.transform, joint.rpy);
}
Material Setup from URDF
// Material definition from URDF
const material = new Material();
material.name = "blue_plastic";
material.color = parseColor("0.2 0.3 0.8 1.0"); // Blue plastic
// Alternative: parse from URDF XML attributes
const colorAttr = xmlElement.getAttribute("rgba");
if (colorAttr) {
material.color = parseColor(colorAttr);
}
Error Handling
Vector Parsing Errors
try {
const position = parseVector("1.0 0.5"); // Missing Z component
} catch (error) {
console.error("Invalid vector format:", error.message);
// Use default value
const position = new BABYLON.Vector3(0, 0, 0);
}
Color Parsing Errors
try {
const color = parseColor("1.0 0.0 0.0"); // Missing alpha
} catch (error) {
console.error("Invalid color format:", error.message);
// Use default color
const color = new BABYLON.Color4(0.5, 0.5, 0.5, 1.0);
}
Safe Parsing with Defaults
function safeParseVector(vec: string, defaultValue: BABYLON.Vector3): BABYLON.Vector3 {
try {
return parseVector(vec);
} catch (error) {
console.warn(`Failed to parse vector "${vec}", using default`);
return defaultValue;
}
}
// Usage
const position = safeParseVector(
urdfOrigin,
new BABYLON.Vector3(0, 0, 0)
);
Coordinate System Handling
ROS to Babylon.js Conversion
The utilities handle coordinate system differences between ROS and Babylon.js:
ROS Coordinate System:
- X: Forward
- Y: Left
- Z: Up
- Rotations: Roll (X), Pitch (Y), Yaw (Z)
Babylon.js Coordinate System: - X: Right - Y: Up - Z: Forward - Rotations: Applied in specific order for proper transformation
Rotation Order
// applyRotationToTransform applies rotations in this order:
// 1. Yaw rotation around Z-axis
// 2. Pitch rotation around Y-axis
// 3. Roll rotation around X-axis
// This is equivalent to:
transformNode.addRotation(0, 0, vec.z) // Yaw (Z)
.addRotation(0, vec.y, 0) // Pitch (Y)
.addRotation(vec.x, 0, 0); // Roll (X)
Common Patterns
URDF XML Parsing
// Typical XML attribute parsing
function parseJointFromXML(jointElement: Element): Joint {
const joint = new Joint();
joint.name = jointElement.getAttribute("name") || "";
// Parse origin
const originElement = jointElement.querySelector("origin");
if (originElement) {
const xyzAttr = originElement.getAttribute("xyz");
const rpyAttr = originElement.getAttribute("rpy");
if (xyzAttr) joint.origin = parseVector(xyzAttr);
if (rpyAttr) joint.rpy = parseRPY(rpyAttr);
}
// Parse axis
const axisElement = jointElement.querySelector("axis");
if (axisElement) {
const xyzAttr = axisElement.getAttribute("xyz");
if (xyzAttr) joint.axis = parseVector(xyzAttr);
}
return joint;
}
Material XML Parsing
function parseMaterialFromXML(materialElement: Element): Material {
const material = new Material();
material.name = materialElement.getAttribute("name") || "";
// Parse color
const colorElement = materialElement.querySelector("color");
if (colorElement) {
const rgbaAttr = colorElement.getAttribute("rgba");
if (rgbaAttr) {
material.color = parseColor(rgbaAttr);
}
}
// Parse texture
const textureElement = materialElement.querySelector("texture");
if (textureElement) {
const filenameAttr = textureElement.getAttribute("filename");
if (filenameAttr) {
material.filename = filenameAttr;
}
}
return material;
}
Performance Considerations
String Parsing Optimization
// Cache parsed values when possible
const positionCache = new Map<string, BABYLON.Vector3>();
function getCachedVector(vec: string): BABYLON.Vector3 {
if (!positionCache.has(vec)) {
positionCache.set(vec, parseVector(vec));
}
return positionCache.get(vec)!;
}
Batch Transformations
// Apply multiple transformations efficiently
function setupTransforms(transforms: Array<{node: BABYLON.TransformNode, rpy: BABYLON.Vector3}>) {
scene.beginAnimation(); // Batch updates
for (const {node, rpy} of transforms) {
applyRotationToTransform(node, rpy);
}
scene.endAnimation();
}
Integration with Robot Loading
The utilities are primarily used during robot loading from URDF:
// In urdf.ts module
export function loadRobot(urdfDoc: Document, scene: BABYLON.Scene): Robot {
const robot = new Robot();
// Parse joints
const jointElements = urdfDoc.querySelectorAll("joint");
for (const jointEl of jointElements) {
const joint = new Joint();
// Use utilities for parsing
const originEl = jointEl.querySelector("origin");
if (originEl) {
joint.origin = parseVector(originEl.getAttribute("xyz") || "0 0 0");
joint.rpy = parseRPY(originEl.getAttribute("rpy") || "0 0 0");
}
robot.joints.set(joint.name, joint);
}
return robot;
}