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.
DSL Operators
Section titled “DSL Operators”+action (unary plus)
Section titled “+action (unary plus)”Enqueues Actions into the current sequence. Actions run in the order they are added:
+claw.open()+claw.close()wait(seconds)
Section titled “wait(seconds)”Inserts a time delay between actions. The argument is in seconds:
+claw.open()wait(0.5)+claw.close()parallel
Section titled “parallel”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()sequence
Section titled “sequence”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() }}instant
Section titled “instant”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)From Simple to Complex
Section titled “From Simple to Complex”Simple sequence
Section titled “Simple sequence”Two actions run back to back:
+claw.open()+claw.close()Adding timing
Section titled “Adding timing”Insert delays between actions:
+claw.open()wait(0.5)+arm.lower()wait(0.3)+claw.close()Parallel execution
Section titled “Parallel execution”Spin up the launcher while driving to position:
parallel { +drivetrain.path { lineTo(launchPose) } +launcher.enable()}+pusher.push()Nested composition
Section titled “Nested composition”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 }Loops and control flow
Section titled “Loops and control flow”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()voltAction Function
Section titled “voltAction Function”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.