Skip to content

Volt Action Builder

Actions are the core execution primitive in Volt — reusable units of robot behavior with init, loop, and cleanup stages. They originate from RoadRunner and are extended by Volt with tracing and composition.

VoltActionBuilder is the DSL class for composing Actions into sequences with timing, parallelism, and control flow. It is used by the then function in AutonomousModes and ManualModes and the voltAction function in other classes (usually Robots).

The builder collects actions into a list and produces a single SequentialAction when built.

Enqueues Actions into the current sequence. Actions run in the order they are added:

+claw.open()
+claw.close()

Inserts a time delay between actions. The argument is in seconds:

+claw.open()
wait(0.5)
+claw.close()

Runs all child actions simultaneously. The block completes when every child has finished:

parallel {
+drivetrain.path { lineTo(launchPose) }
+launcher.enable()
}
// both are done before this runs
+classifier.releaseArtifact()

Runs child actions one after another. This is the explicit form of what the top-level builder does implicitly. It can be used to create a sequential action inside a parallel block:

parallel {
+drivetrain.path { lineTo(pose) }
sequence {
+launcher.enable()
wait(1.0)
+pusher.push()
}
}

Executes a block of code immediately as a one-shot action. Use it for state mutations, telemetry updates, or any synchronous side effect that does not need a loop:

instant { targetVelocity = 1500.0 }
+launcher.enable(targetVelocity)

Two actions run back to back:

+claw.open()
+claw.close()

Insert delays between actions:

+claw.open()
wait(0.5)
+arm.lower()
wait(0.3)
+claw.close()

Spin up the launcher while driving to position:

parallel {
+drivetrain.path { lineTo(launchPose) }
+launcher.enable()
}
+pusher.push()

A parallel block where one branch is itself a sequence:

parallel {
+drivetrain.path { lineTo(launchPose) }
sequence {
+launcher.enable()
wait(1.0)
+classifier.releaseArtifact()
}
}
parallel {
+launcher.disable()
+drivetrain.path { lineTo(finalPose) }
}
instant { blackboard["endPose"] = drivetrain.pose }

Standard Kotlin control flow works inside the builder. The builder lambda is regular Kotlin code, only +, wait, parallel, sequence, and instant interact with the action queue:

repeat(amount) {
+launcher.enable()
+storage.release()
wait(0.6)
+storage.close()
wait(0.4)
}
+launcher.disable()

While VoltActionBuilder is used internally by Event bindings, you can also use it directly in Robot subclasses to compose Actions from Attachments into higher-level behaviors. The voltAction function is the entry point for this:

fun fireAllStoredArtifacts(targetVelocity: Double) = voltAction {
+launcher.enable(targetVelocity)
+classifier.releaseAllArtifacts()
+launcher.disable()
}

voltAction returns a standard RoadRunner Action that can itself be enqueued with + inside other builders or bound to events.