Spaces:
Running
Running
| import { XMLParser } from "npm:fast-xml-parser@4.3.5"; | |
| import { serve } from "https://deno.land/std@0.168.0/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", | |
| }, | |
| } | |
| ); | |
| } | |
| }); | |