Tutorial¶
Learn the DAM mental model by building one Stackfile, running it, and reading what the guard stack tells you. Takes about 30 minutes.
The Problem¶
You have a robot and an ML policy. The policy always outputs the next action -- it has no idea when that action is unsafe. In simulation everything looks fine. On hardware, the policy grabs the wrong thing, bumps into objects, or pushes joints too hard.
DAM intercepts every action and tells you what happened: passed, clamped (adjusted to stay safe), or rejected (replaced by a fallback). The goal is not to hide failures -- it is to make them visible.
Step 1: Understand the Guard Stack¶
Four independent layers evaluate every action:
Policy Output
↓
[ L0 OOD ] Is the observation familiar?
[ L1 Motion ] Are joints and workspace safe?
[ L2 Task ] Does this fit the task?
[ L3 Hardware ] Is the robot healthy?
↓
DECISION: Pass / Clamp / Reject
The most restrictive decision wins. If L1 says CLAMP and L2 says REJECT, the action is rejected.
Fail-to-reject: if a guard crashes, times out, or throws an exception, the action is rejected. The system is conservative by default.
For a deeper look at each layer, see Guard Stack Explained.
Step 2: Write a Minimal Stackfile¶
A Stackfile is a YAML file that configures everything DAM needs -- guards, boundaries, tasks -- without writing Python code.
Start from the minimum:
dam:
version: "1"
guards:
- L1: motion
phase: 0
- L2: execution
phase: 1
- L3: hardware
always: true
boundaries:
joint_position_limits:
layer: L1
type: single
nodes:
- callback: joint_position_limits
params:
upper: [1.57, 1.57, 1.57, 1.57, 1.57, 0.08]
lower: [-1.57, -1.57, -1.57, -1.57, -1.57, 0.0]
tasks:
demo:
boundaries: [joint_position_limits]
This enables L1 motion guard with joint limits. Any action that pushes a joint past 1.57 rad gets clamped back.
Validate it:
For full Stackfile options, see Stackfile Walkthrough and Common Edits.
Step 3: Add Boundaries¶
Boundaries define the safety envelope. Two types:
Single -- one set of constraints for the entire task:
boundaries:
joint_velocity_limit:
layer: L1
type: single
nodes:
- callback: joint_velocity_limit
params:
max_velocities: [1.5, 1.5, 1.5, 1.5, 1.5, 0.5]
List -- multiple phases, advanced sequentially:
boundaries:
pick_and_place:
layer: L2
type: list
nodes:
- callback: task_workspace_bounds
params:
bounds: [[-0.35, 0.35], [-0.05, 0.45], [0.01, 0.40]]
fallback: hold_position
timeout_sec: 15.0
- callback: task_workspace_bounds
params:
bounds: [[-0.20, 0.20], [0.05, 0.35], [0.01, 0.15]]
fallback: hold_position
timeout_sec: 8.0
When a constraint is violated, the fallback fires: hold_position, retreat, or emergency_stop.
For boundary design patterns, see Boundary System.
Step 4: Run It¶
Or from Python:
import dam
summary = dam.run("my_stackfile.yaml", task="demo", cycles=200)
print(summary.status, summary.cycles, summary.emergency)
Open the console at http://localhost:3000 and watch guard decisions in real time.
Step 5: Read What Happened¶
Every cycle produces telemetry. The console shows it live; the API lets you query it:
curl http://localhost:8080/api/telemetry/history # last N cycles
curl http://localhost:8080/api/risk-log/stats # aggregate stats
curl http://localhost:8080/api/risk-log/export/json # full export
When an action is rejected, DAM captures +/-30 seconds of context in MCAP format for post-incident analysis.
The key question is not "did it work?" It is: where did the policy start to break down, and which guard caught it?
Step 6: Prepare for Hardware¶
Before connecting real hardware, work through this checklist:
- [ ] Stackfile validates:
dam validate mystack.yaml - [ ] Demo runs without errors in simulation
- [ ] Fallbacks tested: manually trigger rejections and verify hold/retreat/e-stop
- [ ] Cycle latency under budget (< 5ms at 50 Hz)
- [ ] Physical e-stop button accessible and tested
See Hardware Readiness for the full checklist.
What You Now Know¶
- The guard stack evaluates every action through four independent layers
- Fail-to-reject: when in doubt, reject
- Stackfiles configure guards, boundaries, and tasks in YAML
- Boundaries define the safety envelope; list boundaries model multi-phase tasks
- The console and API show you where the policy breaks down, not just whether it succeeded
Next Steps¶
- Use Cases -- how DAM helps at each stage of the ML pipeline
- Guard Stack Explained -- deep dive into each layer
- Safety Model -- what DAM does and does not guarantee
- Troubleshooting -- common first-run issues
- Glossary -- quick term reference