Spaces:
Running
Running
import { XMLParser } from "npm:[email protected]"; | |
import { serve } from "https://deno.land/[email protected]/http/server.ts"; | |
interface UrdfLink { | |
name: string; | |
mass: number; | |
inertia: { | |
ixx: number; | |
ixy: number; | |
ixz: number; | |
iyy: number; | |
iyz: number; | |
izz: number; | |
}; | |
has_visual: boolean; | |
has_collision: boolean; | |
} | |
interface UrdfJoint { | |
name: string; | |
type: string; | |
parent: string; | |
child: string; | |
limits?: { | |
lower: number; | |
upper: number; | |
effort: number; | |
velocity: number; | |
}; | |
} | |
const corsHeaders = { | |
"Access-Control-Allow-Origin": "*", | |
"Access-Control-Allow-Headers": | |
"authorization, x-client-info, apikey, content-type", | |
"Access-Control-Allow-Methods": "POST, OPTIONS", | |
}; | |
serve(async (req) => { | |
// Handle CORS preflight requests | |
if (req.method === "OPTIONS") { | |
return new Response("ok", { headers: corsHeaders }); | |
} | |
try { | |
if (req.method !== "POST") { | |
throw new Error("Method not allowed"); | |
} | |
const { urdfContent } = await req.json(); | |
if (!urdfContent) { | |
throw new Error("No Urdf content provided"); | |
} | |
// Parse Urdf XML using fast-xml-parser | |
const parser = new XMLParser({ | |
ignoreAttributes: false, | |
attributeNamePrefix: "", | |
parseAttributeValue: true, | |
}); | |
const doc = parser.parse(urdfContent); | |
if (!doc || !doc.robot) { | |
throw new Error("No robot element found in Urdf"); | |
} | |
// Extract robot data | |
const robotElement = doc.robot; | |
const name = robotElement.name || "unnamed_robot"; | |
const version = robotElement.version; | |
const links: UrdfLink[] = []; | |
const joints: UrdfJoint[] = []; | |
let total_mass = 0; | |
// Parse links | |
if (robotElement.link) { | |
const linkElements = Array.isArray(robotElement.link) | |
? robotElement.link | |
: [robotElement.link]; | |
linkElements.forEach((link: any) => { | |
const linkName = link.name || ""; | |
const inertial = link.inertial; | |
const mass = inertial?.mass?.value || 0; | |
total_mass += mass; | |
const linkData: UrdfLink = { | |
name: linkName, | |
mass, | |
inertia: { | |
ixx: 0, | |
ixy: 0, | |
ixz: 0, | |
iyy: 0, | |
iyz: 0, | |
izz: 0, | |
}, | |
has_visual: !!link.visual, | |
has_collision: !!link.collision, | |
}; | |
// Parse inertia | |
if (inertial?.inertia) { | |
const inertiaEl = inertial.inertia; | |
linkData.inertia = { | |
ixx: inertiaEl.ixx || 0, | |
ixy: inertiaEl.ixy || 0, | |
ixz: inertiaEl.ixz || 0, | |
iyy: inertiaEl.iyy || 0, | |
iyz: inertiaEl.iyz || 0, | |
izz: inertiaEl.izz || 0, | |
}; | |
} | |
links.push(linkData); | |
}); | |
} | |
// Parse joints | |
if (robotElement.joint) { | |
const jointElements = Array.isArray(robotElement.joint) | |
? robotElement.joint | |
: [robotElement.joint]; | |
jointElements.forEach((joint: any) => { | |
const jointData: UrdfJoint = { | |
name: joint.name || "", | |
type: joint.type || "", | |
parent: joint.parent?.link || "", | |
child: joint.child?.link || "", | |
}; | |
// Parse limits | |
if (joint.limit) { | |
jointData.limits = { | |
lower: joint.limit.lower || 0, | |
upper: joint.limit.upper || 0, | |
effort: joint.limit.effort || 0, | |
velocity: joint.limit.velocity || 0, | |
}; | |
} | |
joints.push(jointData); | |
}); | |
} | |
const response = { | |
success: true, | |
data: { | |
name, | |
version, | |
links, | |
joints, | |
total_mass, | |
num_links: links.length, | |
num_joints: joints.length, | |
}, | |
}; | |
return new Response(JSON.stringify(response), { | |
headers: { | |
...corsHeaders, | |
"Content-Type": "application/json", | |
}, | |
}); | |
} catch (error) { | |
console.error("Error parsing Urdf:", error); | |
return new Response( | |
JSON.stringify({ | |
success: false, | |
error: | |
error instanceof Error ? error.message : "Unknown error occurred", | |
}), | |
{ | |
status: 500, | |
headers: { | |
...corsHeaders, | |
"Content-Type": "application/json", | |
}, | |
} | |
); | |
} | |
}); | |