RasmahRasmah

Trusses: A Gable Roof Frame (1D Bar FEA)

using Rasmah
using LinearAlgebra

Overview

A truss is a structure made of pin-jointed bars that carry only axial load — no bending. Roof frames, crane jibs, bridges, and radio masts are trusses because they use material at maximum efficiency: every bar is in pure tension or compression. The analysis is the oldest finite-element method there is: each bar is a 1-D element of axial stiffness EA/L, the bars are assembled into a global stiffness, and K u = f is solved for the joint displacements. From those, the axial force in every member follows.

This tutorial builds a gable roof frame — the classic triangle: two rafters and a tie beam, spanning 8 m with a 1.5 m rise, carrying a 10 kN snow load at the apex. The member forces of this frame can be found by hand with the method of joints, which is exactly how we verify the finite-element answer.

The method of joints

At the apex C the two rafters share the load. Each rafter makes the angle θ with the horizontal, so vertical equilibrium gives

\[ N_{rafter} = -\frac{P}{2\sin\theta}, \]

and horizontal equilibrium at the roller support gives the tie tension N_tie = P/(2 tan θ). With P = 10 kN, a span of 8 m and a rise of 1.5 m, sin θ = 1.5/√(4² + 1.5²) and the numbers come out as below.

Building the frame

Three joints — the two supports A, B and the apex C — and three members. One support is pinned, the other rolls horizontally, so the frame is statically determinate and the tie carries the rafter thrust:

span, rise = 8.0, 1.5
nodes = [0.0 span   span / 2;                     # A, B, C
         0.0 0.0    rise;
         0.0 0.0    0.0]
struts = [1 3 1;                                  # A-C, C-B, A-B
          3 2 2]
t = Truss(nodes, struts)

println("nodes = ", num_nodes(t), ", struts = ", num_struts(t))
println("total member length = ", round(ustrip(total_length(t)); digits = 2), " m")
nodes = 3, struts = 3
total member length = 16.54 m

Stiffness and solve

Each bar contributes EA/L · [n̂n̂ᵀ −n̂n̂ᵀ; −n̂n̂ᵀ n̂n̂ᵀ] at its two joints. The rafters are a pair of L 70 × 70 × 6 angles (A ≈ 8.13 cm² each) in S235 steel. Pin A, let B roll (restrain only its y), fix the out-of-plane z dofs, and hang 10 kN from the apex:

E, A = 2.10e11, 8.13e-4                        # steel, 8.13 cm² per member

K = truss_stiffness(t, steel, A)
println("K is symmetric: ", K ≈ K')
println("K size: ", size(K))

fixed = [1, 2, 3, 5, 6, 9]                      # A pinned, B rolls, z dofs out
loads = zeros(9); loads[8] = -10000.0          # −10 kN at the apex C

u = solve_truss(t, steel, A, fixed, loads)
println("apex displacement (mm): ", round.(u[7:9] * 1e3; digits = 2))
K is symmetric: true
K size: (9, 9)
apex displacement (mm): [0.33, -1.94, 0.0]

Member forces vs. the method of joints

N = truss_axial_forces(t, steel, A, u)
θ = atan(rise, span / 2)

println("member        FEM (N)      hand (N)")
println("rafters       ", round(N[1]; digits = 0), "     ", round(-10000 / (2 * sin(θ)); digits = 0))
println("tie           ", round(N[3]; digits = 0), "      ", round(10000 / (2 * tan(θ)); digits = 0))
member        FEM (N)      hand (N)
rafters       -14240.0     -14240.0
tie           13333.0      13333.0

The finite-element member forces match the method-of-joints values to the last digit — the rafters carry 14.2 kN in compression and the tie 13.3 kN in tension (negative = compression). Notice how the tie tension exceeds the applied load: the shallow θ amplifies the horizontal thrust, which is why gable frames need a sturdy tie or buttresses.

A grid truss (and why it needs bracing)

grid_truss(nx, ny, nz, spacing) builds a rectangular grid with struts only along the grid edges — it is a mechanism without diagonals (the reduced stiffness is singular). Add diagonal bracing (or a full ground structure) to make it stable before solving:

g = grid_truss(3, 2, 1, 1.0)
println("grid truss: nodes = ", num_nodes(g), ", struts = ", num_struts(g))
grid truss: nodes = 6, struts = 7

Notes

  • truss_stiffness, solve_truss, truss_axial_forces, truss_compliance are the FEA primitives; the truss Truss struct is also used by the robotics assembly planner (assemble_sequence, rrt_path, plan_assembly).
  • solve_truss reduces the system with a Cholesky solve, so the supported structure must be stable (no rigid-body modes or mechanisms).

Next steps

  • Beams — the bending members a truss deliberately avoids.
  • Topology optimization — the ground-structure truss problem behind solve_truss’s design sibling.
  • Assembly mates — putting pinned parts like these together.