A design with components and joints exports as a URDF robot description (file.export to .urdf, the MCP export tool, solidcraft-cli run --out, File > Export URDF...). It writes one binary STL per component in metres, links with mass, centre of mass and inertia from material density, and maps rigid, revolute, slider, cylindrical, pin-slot, planar and ball joints to URDF joints or short chains. Loops, broken joints and loose parts are reported as warnings. Options: mesh_prefix, effort, velocity. Docs in docs/urdf.md.
This commit is contained in:
1 parent
d2e409f40c
commit
17db109c5d
19 files changed
+1993
-17
No files matched your search
@@ -103,6 +103,24 @@ fn handshake_and_tools_list() {
|
||||
assert_eq!(call(&mut s, 8, "nope/nope", json!({}))["error"]["code"], -32601);
|
||||
}
|
||||
|
||||
/// A URDF goes through `export` with its own options (#719).
|
||||
#[test]
|
||||
fn export_tool_writes_a_urdf_package() {
|
||||
let mut s = server();
|
||||
tool(&mut s, "execute", json!({"command": "solid.box", "params": {"length": 10, "width": 10, "height": 10}}));
|
||||
let dir = std::env::temp_dir().join(format!("solidcraft-mcp-urdf-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let urdf = dir.join("robot.urdf");
|
||||
let r = tool(&mut s, "export", json!({"path": urdf.to_string_lossy(), "mesh_prefix": "package://robot/meshes/"}));
|
||||
assert_eq!(r["format"], "Urdf", "{r}");
|
||||
assert!(std::fs::read_to_string(&urdf).unwrap().contains(r#"filename="package://robot/meshes/robot-base.stl""#));
|
||||
assert!(dir.join("robot-base.stl").exists());
|
||||
// effort and velocity reach file.export, which refuses a bad one.
|
||||
let r = raw_tool(&mut s, "export", json!({"path": urdf.to_string_lossy(), "effort": -1}));
|
||||
assert_eq!(r["result"]["isError"], json!(true), "{r}");
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// Box → fillet → hole in one batch, then verify with measure / inspect_design and look at it.
|
||||
#[test]
|
||||
fn agent_builds_box_fillet_hole() {
|
||||
|
||||
@@ -190,12 +190,17 @@ pub fn tool_definitions() -> Vec<Value> {
|
||||
"export",
|
||||
"Export",
|
||||
"Export bodies to STEP (.step/.stp), 3MF (.3mf), binary STL (.stl), ASCII STL (format stla) or OBJ. The format \
|
||||
comes from the extension unless given.",
|
||||
comes from the extension unless given. URDF (.urdf) exports the whole assembly for robot simulators: a link per \
|
||||
component placement with mass and inertia, joints from the assembly's joints, and STL meshes in metres written \
|
||||
next to it (docs/urdf.md); RViz needs mesh_prefix such as package://robot/meshes/.",
|
||||
obj(
|
||||
json!({
|
||||
"path": string("Output file"),
|
||||
"format": {"type": "string", "enum": ["step", "3mf", "3mf-tagged", "stl", "stla", "obj"]},
|
||||
"bodies": {"type": "array", "items": {"type": "string"}, "description": "Body names (default: all)"},
|
||||
"format": {"type": "string", "enum": ["step", "3mf", "3mf-tagged", "stl", "stla", "obj", "urdf"]},
|
||||
"bodies": {"type": "array", "items": {"type": "string"}, "description": "Body names (default: all; not with urdf)"},
|
||||
"mesh_prefix": string("urdf: put before each mesh file name (default: none, so relative to the .urdf)"),
|
||||
"effort": {"type": "number", "description": "urdf: joint effort limit, N or N m (default 1000)"},
|
||||
"velocity": {"type": "number", "description": "urdf: joint velocity limit, m/s or rad/s (default 10)"},
|
||||
}),
|
||||
&["path"],
|
||||
),
|
||||
@@ -387,7 +392,7 @@ fn dispatch(b: &mut dyn Backend, name: &str, a: &Map<String, Value>) -> Result<V
|
||||
p["expression"] = a.get("value").cloned().unwrap_or(Value::Null);
|
||||
exec(b, "parameters.change", p)
|
||||
}
|
||||
"export" => exec(b, "file.export", pick(a, &["path", "format", "bodies"])),
|
||||
"export" => exec(b, "file.export", pick(a, &["path", "format", "bodies", "mesh_prefix", "effort", "velocity"])),
|
||||
"crash_reports" => match a.get("id") {
|
||||
Some(_) => exec(b, "diagnostics.crash_report", pick(a, &["id"])),
|
||||
None => exec(b, "diagnostics.crash_reports", pick(a, &["limit"])),
|
||||
|
||||
Reference in new issue
Block a user