RasmahRasmah

Robot Path Planning for Truss Assembly

Overview

The Truss / RRT (rapidly-exploring random tree) subsystem is the design → fabrication loop for node-and-strut space frames: generate a parametric truss, sequence its assembly into a stable order, and plan collision-free robot paths for each strut through an SDF obstacle scene.

using Rasmah
using LinearAlgebra
using Random
Random.seed!(1)          # deterministic RRT for the tutorial
TaskLocalRNG()

A parametric grid truss

grid_truss(nx, ny, nz, spacing) builds an nx × ny × nz node lattice with struts along every grid edge. Inspect it with num_nodes, num_struts, strut_length, and total_length:

t = grid_truss(2, 2, 2, 1.0)
println(num_nodes(t))               # 8
println(num_struts(t))              # 12
println(strut_length(t, 1))         # 1.0
println(total_length(t))            # 12.0
8
12
1.0
12.0 m

Staged assembly sequencing

assemble_sequence(t, start) orders the struts with a BFS over the strut graph so that every strut connects to a node already in the partial structure — keeping each intermediate frame stable and every strut reachable:

seq = assemble_sequence(t, 1)
println(length(seq) == num_struts(t))

# every strut connects to a previously-placed node
placed = Set{Int}(1)
all_ok = true
for k in seq
    a, b = t.struts[1, k], t.struts[2, k]
    global all_ok = all_ok && ((a in placed) || (b in placed))
    push!(placed, a, b)
end
println("stable at every step: ", all_ok)
true
stable at every step: true

Collision-free RRT paths

rrt_path(start, goal, obstacle, lo, hi) grows a rapidly-exploring random tree, treating obstacle(x) < 0 as “inside” (blocked). It returns the start → goal path, or nothing when it cannot connect:

obstacle = to_sdf(box(0.4, 0.4, 0.4))
p = rrt_path([2.0, 0.0, 0.0], [-2.0, 0.0, 0.0], obstacle, [-3.0, -3.0, -3.0], [3.0, 3.0, 3.0])
println(p !== nothing)
println(norm(p[1] .- [2.0, 0.0, 0.0]) < 1e-9)     # starts at start
println(norm(p[end] .- [-2.0, 0.0, 0.0]) < 1e-9)  # ends at goal
println(length(p), " waypoints")
true
true
true
55 waypoints

A full build plan

plan_assembly(t, obstacle; lo, hi, pick, start) combines the two: the staged strut order plus a collision-free pick → place path for each strut (the strut’s midpoint is the place pose, pick is the pickup pose):

seq, paths = plan_assembly(t, obstacle;
    lo=[-3.0, -3.0, -3.0], hi=[3.0, 3.0, 3.0], pick=[3.0, 3.0, 3.0])
println(length(seq) == num_struts(t))
println(length(paths) == num_struts(t))
println(length(paths[1]), " waypoints in the first strut's path")
true
true
68 waypoints in the first strut's path

Next steps